From 6998ae47aaffe0125dc552509426279b7c6cf70c Mon Sep 17 00:00:00 2001 From: teahubxyz Date: Thu, 15 Oct 2026 10:48:28 -0700 Subject: [PATCH] Orgchain v1.10: keyrings, each key signing in its own chain's standard A new lineage/v0 op binds a node's keys in one inscription whose parent is the node itself: its Taproot and SegWit addresses, its npub and its Ethereum address. Every key signs the same statement the way its own wallets sign a message: BIP-322 simple signatures for the Bitcoin addresses, a NIP-01 note (kind 1, created_at 0) for the npub, EIP-191 for Ethereum. The reducer checks every proof, binds a standing keyring's keys to its node, lets the newest keyring replace the older, and retires keyrings at a graduation (the keys change with the new root) and at a close. Every account gets an Ethereum key at m/44'/60'/account'/0/0; an org's, at account 0, is the key tree page's legal-control key and matches its published vector. Keyring is the ninth verb; Inspect shows each node's keyring and the statement its keys signed, and Reveal its Ethereum private key. The sample publishes three keyrings, and lineage's retires when it graduates. Tests pin BIP-322's published vectors and values cross-checked with bip322-js, ethers and nostr-tools. The regtest rehearsal, rerun with five keyrings, confirmed 89 transactions on Bitcoin Core; ord's 26 events fold to the same trees and keyrings, every proof checked from ord's copy, and the fixture is re-recorded. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01H4upF5LVwmPDDqrhdUfnXh --- AGENTS.md | 9 +- PROVENANCE.md | 10 +- README.md | 56 ++++---- SPEC.md | 72 +++++++++-- bin/lineage-index.mjs | 2 + index.html | 12 +- src/adapters/lineage-keys.js | 21 ++- src/main.js | 45 ++++++- src/orgchain.css | 4 + src/orgchain/actions.js | 50 ++++++-- src/orgchain/keyring.js | 176 ++++++++++++++++++++++++++ src/orgchain/keys.js | 22 +++- src/orgchain/lineage.js | 34 ++++- tests/fixtures/regtest-rehearsal.json | 2 +- tests/indexer.test.js | 8 +- tests/keyring.test.js | 170 +++++++++++++++++++++++++ tests/keys.test.js | 8 +- tests/lab.test.js | 3 + tests/money.test.js | 9 +- tests/orgchain.spec.js | 26 +++- tools/regtest/README.md | 5 +- tools/regtest/rehearse.mjs | 13 +- 22 files changed, 673 insertions(+), 84 deletions(-) create mode 100644 src/orgchain/keyring.js create mode 100644 tests/keyring.test.js diff --git a/AGENTS.md b/AGENTS.md index 5c4c4c7..b8a1c59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,8 +24,13 @@ Orgchain is lineage's app for creating and operating lineage holdings on Super T - Keys follow the tree (`src/orgchain/keys.js`): store roots only (one per holding, one per graduated org) and derive every other key from its position. Every act is signed by whichever key holds the authorizing inscription. - A node's chain key is its account's BIP-86 Taproot key (`m/86'/1'/account'/0/0`); SegWit is BIP-84 at the same - account and holds its money. Leaves are HKDF-SHA256 (salt `lineage/v0`) and must stay byte for byte with lineage's key tree page; - `tests/keys.test.js` holds values read off that page. + account and holds its money; its Ethereum key is BIP-44 at `m/44'/60'/account'/0/0` (an org's, at account 0, is the + key tree page's legal-control key, and `tests/keyring.test.js` pins that page's vector). Leaves are HKDF-SHA256 + (salt `lineage/v0`) and must stay byte for byte with lineage's key tree page; `tests/keys.test.js` holds values read + off that page. +- Keyrings (`src/orgchain/keyring.js`): every key signs the statement with its own chain's message standard (BIP-322, + EIP-191, a NIP-01 event), so real wallets can make and check the proofs. Keep those formats exact and their pinned + vectors passing; a new chain's key joins only with its own standard and a vector to pin. - Secrets show only behind Reveal, reset on every selection, and match the key tree page byte for byte (the tests pin hashes of the page's own output). - The page makes no network requests; keep it that way (the deployed CSP sets `connect-src 'none'`). diff --git a/PROVENANCE.md b/PROVENANCE.md index c1ff598..d0f008a 100644 --- a/PROVENANCE.md +++ b/PROVENANCE.md @@ -14,14 +14,16 @@ The upstream CC0 legal text is retained unchanged at [`public/licenses/supertest Runtime dependencies are pinned in `package.json` and `package-lock.json`: - **@cmdcode/tapscript 1.5.3**, Christopher Scott, [upstream](https://github.com/cmdruid/tapscript), CC-BY-1.0. Used for transaction encoding, signing/verification, Taproot commitments and addresses, and the BIP-143 digests and signatures of SegWit payments. Installed package license retained unchanged at [`public/licenses/tapscript.txt`](public/licenses/tapscript.txt). Library source is unmodified; Vite bundles/minifies it for the browser. -- **@noble/curves 1.9.7**, Paul Miller and contributors, [upstream](https://github.com/paulmillr/noble-curves), MIT. Used for key generation/validation and public keys, and to verify the low-S DER signatures of SegWit payments: secp256k1 for chain and nostr keys, Ed25519 and X25519 for lineage's leaves. License retained at [`public/licenses/noble-curves.txt`](public/licenses/noble-curves.txt). -- **@noble/hashes 1.8.0**, Paul Miller and contributors, [upstream](https://github.com/paulmillr/noble-hashes), MIT. Used for synthetic block hashes, BIP-85's HMAC, the leaves' HKDF-SHA256 and the RIPEMD-160 of P2WPKH key hashes. License retained at [`public/licenses/noble-hashes.txt`](public/licenses/noble-hashes.txt). -- **@scure/base 1.2.6**, Paul Miller, [upstream](https://github.com/paulmillr/scure-base), MIT. Used for bech32 npubs and base64 leaf keys. License retained at [`public/licenses/scure-base.txt`](public/licenses/scure-base.txt). -- **@scure/bip32 1.7.0**, Patricio Palladino and Paul Miller, [upstream](https://github.com/paulmillr/scure-bip32), MIT. Used for HD derivation under the BIP-85, BIP-86, BIP-84 and NIP-06 paths. License retained at [`public/licenses/scure-bip32.txt`](public/licenses/scure-bip32.txt). +- **@noble/curves 1.9.7**, Paul Miller and contributors, [upstream](https://github.com/paulmillr/noble-curves), MIT. Used for key generation/validation and public keys, to verify the low-S DER signatures of SegWit payments, and to make and check keyrings' proofs (BIP-340, low-S ECDSA, and the public-key recovery EIP-191 relies on): secp256k1 for chain, nostr and Ethereum keys, Ed25519 and X25519 for lineage's leaves. License retained at [`public/licenses/noble-curves.txt`](public/licenses/noble-curves.txt). +- **@noble/hashes 1.8.0**, Paul Miller and contributors, [upstream](https://github.com/paulmillr/noble-hashes), MIT. Used for synthetic block hashes, BIP-85's HMAC, the leaves' HKDF-SHA256, the RIPEMD-160 of P2WPKH key hashes, the tagged hashes of BIP-322, and the Keccak-256 of Ethereum addresses (EIP-55) and EIP-191. License retained at [`public/licenses/noble-hashes.txt`](public/licenses/noble-hashes.txt). +- **@scure/base 1.2.6**, Paul Miller, [upstream](https://github.com/paulmillr/scure-base), MIT. Used for bech32 npubs, base64 leaf keys, and the bech32 and bech32m addresses and base64 BIP-322 signatures in keyrings. License retained at [`public/licenses/scure-base.txt`](public/licenses/scure-base.txt). +- **@scure/bip32 1.7.0**, Patricio Palladino and Paul Miller, [upstream](https://github.com/paulmillr/scure-bip32), MIT. Used for HD derivation under the BIP-85, BIP-86, BIP-84, NIP-06 and BIP-44 Ethereum paths. License retained at [`public/licenses/scure-bip32.txt`](public/licenses/scure-bip32.txt). - **@scure/bip39 1.6.0**, Patricio Palladino and Paul Miller, [upstream](https://github.com/paulmillr/scure-bip39), MIT. Used for the 24-word lab roots and their seeds. License retained at [`public/licenses/scure-bip39.txt`](public/licenses/scure-bip39.txt). Five local changes to the engine, all original code in `src/adapters/chain.js`, tested in `tests/money.test.js`, with Super Testnet's tests (`tests/adapters.test.js`) passing unchanged. Orgchain v1.5: the chain also accepts native SegWit (P2WPKH) outputs and SIGHASH_ALL P2WPKH spends, verified per BIP-143, so lineage accounts can hold and send test BTC at their BIP-84 addresses; everything about inscriptions stays Taproot-only. Orgchain v1.6: a coinbase may split the block reward across up to 64 outputs (`mineTo`; `mine` still pays one script), so one beat can pay several holdings. Orgchain v1.7: ordinary (non-reveal) spends may take up to eight inputs and outputs (`MAX_IO`), and their key-path Taproot signatures may carry SIGHASH_SINGLE|ANYONECANPAY (0x83, the sell-order flag), so one transaction can carry a deal: an item, the buyer's coins, the price and change. Reveals keep their two-in, two-out shape and default signatures. Orgchain v1.9: a chain may start from coins imported from a real chain (`importCoin`; `MetadataIndex` numbers their sats the same way, `importRanges` in `src/adapters/sats.js`), so the regtest rehearsal can broadcast the lab's transactions byte for byte; and a reveal's script path is checked per BIP-341 and BIP-342 against the exact script bytes (`tapscriptValid`), with tapscript's own check kept as a fallback so labs saved earlier still load. That rehearsal also found that the inscription adapter (`src/adapters/inscription.js`, adapted from inscriptions-online) committed its reveals to tapscript's `encodeScript` of a hex script, which re-encodes one-byte pushes, so real Bitcoin rejected them; it now commits to the exact bytes (`tapleafOf`). Tested in `tests/indexer.test.js`. +Keyrings (`src/orgchain/keyring.js`, original code) sign with each chain's own message standard: BIP-322 simple signatures, EIP-191 `personal_sign`, and a NIP-01 event. `tests/keyring.test.js` pins BIP-322's published vectors, and values that bip322-js 3.0.0, ethers 6 and nostr-tools 2 produced or accepted in a one-time cross-check; none of those is a dependency. + Vite and Playwright are build/test dependencies, not runtime network services. Their installed package notices remain in the locked dependency installation. No unlicensed upstream code was copied. The bounded JSON/CBOR codec, byte-derived MetadataIndex, trusted event-counter reducer, local API facade and persisted auto-miner schedule are original adapter code. Metadata encoding and endpoint naming were checked against the [Ordinals metadata](https://docs.ordinals.com/inscriptions/metadata.html) and [endpoint](https://docs.ordinals.com/inscriptions/recursion.html) references; no ord source code was copied. diff --git a/README.md b/README.md index f00c287..9c94306 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ Lineage gives an org its structure, a key tree with a place for every org and ag inscription on a private toy chain in your browser, and its parent inscription is the node that authorizes it, so the chain itself records who did what, and when. -- **Found** a holding (a root: the LLC). **Birth** orgs and agents under any org. **Award** a belt (one skill, one - seat, in any holding: a registry like well-known certifies agents it doesn't hold). **Decide** (a decision on a - node's record). **Make** an item (an inscription its maker holds, and can sell). **Graduate** an org: its edge flips - from derived to adopted, and it becomes a holding of its own, with its own tree, timeline and share of the mining, - while its parent's tree keeps a row for it. **Close** a node (derived children close with it; graduated ones hold - their own roots and stay open). +- **Found** a holding (a root: the LLC). **Birth** orgs and agents under any org. **Award** a belt (one skill, one seat, + in any holding: a registry like well-known certifies agents it doesn't hold). **Decide** (a decision on a node's + record). **Make** an item (an inscription its maker holds, and can sell). **Keyring** (a node publishes its keys on + each chain, each key signing the same statement). **Graduate** an org: its edge flips from derived to adopted, and it + becomes a holding of its own, with its own tree, timeline and share of the mining, while its parent's tree keeps a row + for it. **Close** a node (derived children close with it; graduated ones hold their own roots and stay open). - **Time.** A beat is a block. At the default tempo each act is its own beat; at 10, 30 or 60 seconds, acts are cued and land together on the next beat; on manual they wait for *Beat now*. The slider and *Replay* show a holding as it stood at any beat. @@ -39,24 +39,32 @@ chain itself records who did what, and when. order book, until it is accepted, withdrawn, or goes stale (a coin it promised moved, or a side closed or re-keyed). The buyer pays the fee; a price of 0 is a free claim. Payments spend coins no offer has promised first. Accepted offers stay as the deals' receipts, and the timeline and Inspect show each deal (`src/orgchain/offers.js`). +- **Keyrings.** **Keyring** publishes a node's keys in one inscription whose parent is the node itself: its Taproot and + SegWit addresses, its npub and its Ethereum address, so another chain or a registry like well-known can find them + without deriving anything. Every key signs the same statement, the way its own wallets sign a message: BIP-322 for the + Bitcoin addresses, a nostr note for the npub, EIP-191 for Ethereum, so any wallet can make a proof and any library can + check one. The newest keyring counts, no key is bound to two nodes at once, and a graduation retires the keyrings it + re-keys, so the graduate publishes its new keys (the sample shows lineage's). Inspect shows each node's keyring and + the statement its keys signed (`src/orgchain/keyring.js`). - **One interpretation.** `src/orgchain/lineage.js` folds `lineage/v0` events into trees, and vets every act before anything is signed. Events it rejects stay on the chain and show as rejected; they just don't change the tree. - **Keys.** Each holding gets its own 24-word lab root, and every node has lineage's keys at its place in the tree (`src/orgchain/keys.js`): an org's seed is BIP-85 from its parent's, or its own root once it graduates; an org is account 0 of its seed and its agents are accounts 1..n. Every account lists its addresses, so no one has to derive them: **Taproot** (BIP-86, `m/86'/1'/account'/0/0`), which holds the node's inscription, signs its acts and receives - inscriptions; **SegWit** (BIP-84, `m/84'/1'/account'/0/0`) for payments; its **Tapkey**, the npub as a Taproot - address (its nostr key with the BIP-86 tweak), which the npub alone finds; and its **npub** (NIP-06). Its **leaves** - hang off the same tree, byte for byte as on lineage's key tree page (`src/orgchain/leaves.js`): an agent's ssh, git, - dkim and wg keys from its nostr secret, an org's ssh-ca, mtls and noise keys from its seed, each with the public line - to paste. Every act is signed by the Taproot key that holds the authorizing inscription, and a birth hands the child - its own. Graduation is a claim by the org's fresh root, countersigned by its derived key, and the derived subtree - re-keys under the new root, so the parent's line can no longer sign for it. Labs keyed by v1.1 or v1.2 keep their - chain keys until they are reset. -- **Secrets.** Each node's Inspect has a Reveal panel, as on lineage's key tree page: its seed (holdings and orgs), - its nsec, its Taproot, SegWit and Tapkey keys as descriptors Bitcoin Core imports as they are (test-network WIF, - BIP-380 checksums), and its leaves' private keys (OpenSSH, DKIM, WireGuard, PKCS#8, Headscale). Hidden again on - every selection; lab keys only. + inscriptions; **SegWit** (BIP-84, `m/84'/1'/account'/0/0`) for payments; its **Tapkey**, the npub as a Taproot address + (its nostr key with the BIP-86 tweak), which the npub alone finds; its **npub** (NIP-06); and its **Ethereum** address + (BIP-44, `m/44'/60'/account'/0/0`; an org's, at account 0, is its legal-control key, as on the key tree page). Its + **leaves** hang off the same tree, byte for byte as on lineage's key tree page (`src/orgchain/leaves.js`): an agent's + ssh, git, dkim and wg keys from its nostr secret, an org's ssh-ca, mtls and noise keys from its seed, each with the + public line to paste. Every act is signed by the Taproot key that holds the authorizing inscription, and a birth hands + the child its own. Graduation is a claim by the org's fresh root, countersigned by its derived key, and the derived + subtree re-keys under the new root, so the parent's line can no longer sign for it. Labs keyed by v1.1 or v1.2 keep + their chain keys until they are reset. +- **Secrets.** Each node's Inspect has a Reveal panel, as on lineage's key tree page: its seed (holdings and orgs), its + nsec, its Taproot, SegWit and Tapkey keys as descriptors Bitcoin Core imports as they are (test-network WIF, BIP-380 + checksums), its Ethereum private key, and its leaves' private keys (OpenSSH, DKIM, WireGuard, PKCS#8, Headscale). + Hidden again on every selection; lab keys only. Test coins and test keys only: a local chain, the lab wallet (the faucet that pays for foundings, and under *Mainnet* the wallet holdings are funded from) and each holding's lab root, kept in this browser (`localStorage`, key @@ -65,7 +73,8 @@ the operator's call. ## Events -`lineage/v0` is the ord metaprotocol (tag 7); the fields are CBOR metadata (tag 5); the body is a short text label. +`lineage/v0` is the ord metaprotocol (tag 7); the fields are CBOR metadata (tag 5); the body is a short text label (a +keyring's is the statement its keys signed). | op | parent inscription (spent to authorize) | metadata | | --- | --- | --- | @@ -74,6 +83,7 @@ the operator's call. | `award` | the issuing org or holding (`to` may sit in any holding) | `to`, `skill`, `belt` (`white`, `green`, `black`) | | `decide` | the deciding node | `title`, `why` | | `make` | the making node, which then holds the item | `name`, `note` | +| `keyring` | the node itself; the newest counts, and a graduation retires it | `taproot`, `segwit`, `nostr`, `ethereum`, and `proof` (each key's signature) | | `graduate` | the child's parent (then the handoff to the child's fresh root); the child becomes a holding | `of` | | `close` | the node itself | none | @@ -92,10 +102,10 @@ fold in, why a parent proves authority, and every rule the reducer applies. The node bin/lineage-index.mjs --ord http://127.0.0.1:8088 [--from ] [--compare ] ``` -`tools/regtest/` rehearses the sample on Bitcoin Core regtest: the lab's own transactions, byte for byte, confirmed by -Bitcoin Core and indexed by `ord`, which then tell the same story as the lab (`tests/indexer.test.js` replays a -recorded run). The first rehearsal found that the lab's reveals committed to the wrong tapleaf, which real Bitcoin -rejects; reveals are now checked the way Bitcoin checks them (`SPEC.md`, section 1). +`tools/regtest/` rehearses the sample, keyrings included, on Bitcoin Core regtest: the lab's own transactions, byte for +byte, confirmed by Bitcoin Core and indexed by `ord`, which then tell the same story as the lab (`tests/indexer.test.js` +replays a recorded run). The first rehearsal found that the lab's reveals committed to the wrong tapleaf, which real +Bitcoin rejects; reveals are now checked the way Bitcoin checks them (`SPEC.md`, section 1). ## Build and test diff --git a/SPEC.md b/SPEC.md index 739ca64..db42bd5 100644 --- a/SPEC.md +++ b/SPEC.md @@ -15,9 +15,9 @@ lineage/v0 uses these fields of the ord envelope ([inscriptions](https://docs.or | tag | field | use | | --- | --- | --- | | 7 | metaprotocol | exactly `lineage/v0`; inscriptions without it are not lineage's | -| 5 | metadata | a CBOR map: `op` and its fields (section 4), all strings, in 520-byte pushes (Orgchain keeps it under 2048 bytes) | +| 5 | metadata | a CBOR map: `op` and its fields (section 4), strings except a keyring's `proof` map, in 520-byte pushes (Orgchain keeps it under 2048 bytes) | | 3 | parent | the inscription id of the node that authorizes the event; exactly one, except for `found` | -| 1 | content type | `text/plain;charset=utf-8`; the body is a short label such as `birth time`, ignored by the rules | +| 1 | content type | `text/plain;charset=utf-8`; the body is a short label such as `birth time` (a keyring's is its statement), ignored by the rules | | 2 | pointer | puts a child's inscription in its own output when the parent is spent first | The body, delegate (tag 11) and properties (tag 17) carry no meaning here; properties may later carry display traits @@ -57,6 +57,7 @@ the inscription moves the authority. | `award` | an active holding or org | `to`, `skill`, `belt` (`white`, `green` or `black`) | `to` (any other active node, in any holding) holds that belt in that skill, replacing its earlier belt in it | | `decide` | an active node | `title` (required), `why` (optional) | a decision on the node's record | | `make` | an active node | `name`, `note` (optional) | an item, made and first held by the node; a node makes one item per name | +| `keyring` | the node itself, active | `taproot`, `segwit`, `nostr`, `ethereum`, and `proof`: each key's signature | the node's keys are bound to it, replacing its earlier keyring (section 8) | | `graduate` | the child's parent, active | `of` (an active org child, not yet adopted) | the edge becomes adopted, and the org becomes a holding of its own (section 5) | | `close` | the node itself, active | none | the node closes, with every active derived descendant; adopted ones stay open | @@ -69,7 +70,8 @@ breaks a rule is rejected: it stays on the chain and changes nothing. Any other A holding is a root: a `found`, or an org that graduated. When an org graduates, it and its descendants still in the old holding re-root under it, and it joins the holdings. Its parent stays its parent, so where it came from stays on the -record, and its old holding's tree keeps a row for it. A graduation event belongs to both holdings. +record, and its old holding's tree keeps a row for it. A graduation event belongs to both holdings. Its keys change with +its new root, and so do its derived descendants', so their keyrings retire (section 8). In Orgchain a graduation is followed by a handoff: the org's fresh root claims its inscription, and the derived key that held it countersigns. After that, only the new root can act for the org. @@ -77,7 +79,9 @@ held it countersigns. After that, only the new root can act for the org. ## 6. Order-sensitive conflicts Where independent events conflict within one block, the block's order decides. These are the cases: a close and an act -by one of its derived descendants; an award and its recipient's close; two foundings with the same name. +by one of its derived descendants; an award and its recipient's close; two foundings with the same name; a keyring and +a graduation or close that retires it; two keyrings that list the same key. Orgchain keeps a keyring and the graduation +that would retire it a block apart. ## 7. Ownership, items and deals @@ -87,22 +91,62 @@ buyer's coins in, and the item to the buyer, the price to the holder and the buy inputs first (SIGHASH_ALL) and the holder countersigns the item's. ord sees the item move, and nothing else needs indexing. -## 8. Keys +## 8. Keys and keyrings -Indexers need no keys. Keys say where a node's inscription is expected to live, and who can sign for it. Each holding -has a 24-word root (BIP-39), and an org's seed is BIP-85 from its parent's (`m/83696968'/39'/0'/24'/i'`) until it -graduates. An org is account 0 of its seed and its agents are accounts 1 to n. Each account holds its inscription at its -BIP-86 Taproot address (`m/86'/coin'/account'/0/0`), keeps its money at BIP-84 SegWit, and has a NIP-06 npub. +Indexers need no keys to fold the trees. Keys say where a node's inscription is expected to live, and who can sign for +it. Each holding has a 24-word root (BIP-39), and an org's seed is BIP-85 from its parent's (`m/83696968'/39'/0'/24'/i'`) +until it graduates. An org is account 0 of its seed and its agents are accounts 1 to n. Each account holds its +inscription at its BIP-86 Taproot address (`m/86'/coin'/account'/0/0`), keeps its money at BIP-84 SegWit, and has a +NIP-06 npub (`m/44'/1237'/account'/0/0`) and an Ethereum address (`m/44'/60'/account'/0/0`). An org's Ethereum key, at +account 0, is its legal-control key: the one that holds its entity NFT. + +A `keyring` publishes a node's keys, so other chains and registries can find them without deriving anything. Its parent +is the node itself. Its metadata lists four keys, each written the way its chain writes it, and a proof from each: + +| field | key | proof, in `proof` under the same name | +| --- | --- | --- | +| `taproot` | the Taproot address that holds the node's inscription, lowercase | a BIP-322 simple signature, base64 | +| `segwit` | its P2WPKH address, lowercase, on the same network | a BIP-322 simple signature, base64 | +| `nostr` | its npub | the BIP-340 signature, in hex, of the NIP-01 event `{pubkey, created_at: 0, kind: 1, tags: [], content: statement}` | +| `ethereum` | its address, in EIP-55 case | an EIP-191 `personal_sign` signature: `0x`, then r, s and v in hex | + +Every proof signs the same statement, one line each: + +``` +lineage/v0 keyring +node: +taproot:
+segwit:
+nostr: +ethereum:
+``` + +The lines are joined by a line feed, with none after the last. Each key signs the way its own wallets sign a message, so +any wallet can make a proof and any library can check one. A Taproot proof is a 64-byte signature (SIGHASH_DEFAULT) or a +65-byte one ending in SIGHASH_ALL; a P2WPKH proof is a low-S DER signature with SIGHASH_ALL and the compressed key. The +inscription's body is the statement, for people to read; the rules rebuild it from the metadata. + +A keyring is rejected unless every key is well formed and every proof checks out. While a node's keyring stands, its keys +are bound to that node, and a keyring that lists a key bound to another node is rejected; a key binds once, whatever +network it is written for. A node's newer keyring replaces its older one and frees the keys it no longer lists. A +graduation retires the keyrings of the graduate and its derived descendants, since their keys change with the new root, +and a close retires the keyrings of the nodes it closes. A retired keyring binds nothing, so the node publishes a new one. + +Lineage's key tree page also makes an agent's keyring as a nostr event (kind 30078, `d` = `lineage/keyring/v0`), signed +by its npub and listing its leaves too. The inscription is the chain's record, with a proof from every key. ## 9. Versions and other chains Tag 7 carries the version. A new version is a new string with its own rules, which v0 indexers ignore. The events and the rules are chain-agnostic. What another chain must supply is its own proof of order and of authority (a signature -by the node's key where nothing is spent). Each holding's events would live on one home chain, and an org-signed -keyring would bind a node's keys across chains. +by the node's key where nothing is spent). Each holding's events would live on one home chain, and its nodes' keyrings +(section 8) bind their keys on the others. Another chain's key joins the keyring in a new version, proven the way that +chain's own wallets sign a message. ## 10. Conformance -`tools/regtest` rehearses Orgchain's sample on Bitcoin Core regtest, byte for byte, and `bin/lineage-index.mjs ---compare` checks that ord and the lab tell the same story: the same events in the same beats, the same metadata and -parents, the same trees, and every inscription in the same output. `tests/indexer.test.js` replays a recorded run. +`tools/regtest` rehearses Orgchain's sample on Bitcoin Core regtest, byte for byte, keyrings included, and +`bin/lineage-index.mjs --compare` checks that ord and the lab tell the same story: the same events in the same beats, +the same metadata and parents, the same trees and keyrings, and every inscription in the same output. +`tests/indexer.test.js` replays a recorded run. `tests/keyring.test.js` checks the proofs against BIP-322's published +vectors, the key tree page's Ethereum vector, and values cross-checked with bip322-js, ethers and nostr-tools. diff --git a/bin/lineage-index.mjs b/bin/lineage-index.mjs index ee398c7..29f303f 100644 --- a/bin/lineage-index.mjs +++ b/bin/lineage-index.mjs @@ -21,6 +21,8 @@ for (const root of state.roots) { const rejected = state.log.filter(e => !e.ok); console.log(`\n${plural(events.length, 'lineage/v0 event')} on ord, ${plural(state.items.size, 'item')}${rejected.length ? `, ${rejected.length} rejected:` : ''}`); for (const e of rejected) console.log(` ${summary(e, state)} (${e.id})`); +const rings = [...state.nodes.values()].filter(n => n.keyring && !n.keyring.retired); +if (rings.length) console.log(`${plural(rings.length, 'keyring')} bind ${plural(state.bound.size, 'key')}: ${rings.map(n => n.name).join(', ')}`); if (values.compare) { const { problems, ...n } = compareWithLab(decodeLab(readFileSync(values.compare, 'utf8')), events); console.log(problems.length ? `\nord and the lab differ:\n${problems.map(p => ` ${p}`).join('\n')}` diff --git a/index.html b/index.html index 51e2da7..e2de527 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Orgchain · Lineage - + @@ -16,7 +16,7 @@

Lineage /

Orgchain

-

Found a holding, then birth its orgs and agents, award belts, record decisions, make and trade items, send test BTC, graduate and close. Each act is an inscription whose parent is the node that authorizes it, paid for with the actor's own gas, and each beat is a block whose 50 test BTC the holdings mine. Lineage gives the structure; the chain adds time.

+

Found a holding, then birth its orgs and agents, award belts, record decisions, make and trade items, publish keyrings, send test BTC, graduate and close. Each act is an inscription whose parent is the node that authorizes it, paid for with the actor's own gas, and each beat is a block whose 50 test BTC the holdings mine. Lineage gives the structure; the chain adds time.

Test coins only @@ -88,7 +88,7 @@

Select a holding, or a node in its tree, to act through it.