diff --git a/README.md b/README.md index 3daccf5..7d89737 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,20 @@ BRC | Standard 225 | [Animated-QR Air-Gap Transport for Arbitrary Payloads (TKQR1)](./peer-to-peer/0225.md) 226 | [Miner-Enforced Resale-Royalty Covenant Tokens (OP_PUSH_TX)](./tokens/0226.md) 227 | [Frictionless On-Chain Onboarding via Pre-Funded Claimable Tokens](./apps/0227.md) +300 | [Bitcom — Universal Bitcoin Computer: Decentralized Protocol Registry and Composition](./scripts/0300.md) +301 | [B — Bitcoin Data Protocol](./scripts/0301.md) +302 | [AIP — Author Identity Protocol](./scripts/0302.md) +303 | [MAP — Magic Attribute Protocol](./scripts/0303.md) +304 | [Sigma — Transaction-Bound Script Signatures](./scripts/0304.md) +305 | [Outpoint Content Addressing](./outpoints/0305.md) +306 | [1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking](./tokens/0306.md) +307 | [1Sat Ordinals — Inscription Envelopes](./tokens/0307.md) +308 | [1Sat Ordinal Collections](./tokens/0308.md) +309 | [BSV-21 Fungible Tokens (JSON / Legacy)](./tokens/0309.md) +310 | [BSV-21 Fungible Tokens (Binary)](./tokens/0310.md) +311 | [BAP — Bitcoin Attestation Protocol](./peer-to-peer/0311.md) +312 | [Bitcoin Schema — Social Data Types](./apps/0312.md) +313 | [Encrypted Group Messaging over Type-42 Key Derivation](./peer-to-peer/0313.md) ## License diff --git a/SUMMARY.md b/SUMMARY.md index 308d554..ef07707 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -19,6 +19,7 @@ * [NotaryHash — Privacy-Preserving Signed-Hash Notarization with SPV-Verifiable Certificates](./apps/0220.md) * [Block Media Format (BMF) — Composable On-Chain Audio/Video](./apps/0224.md) * [Frictionless On-Chain Onboarding via Pre-Funded Claimable Tokens](./apps/0227.md) +* [Bitcoin Schema — Social Data Types](./apps/0312.md) ## Wallet @@ -101,6 +102,11 @@ * [Bare Multi-Signature](./scripts/0047.md) * [Pay to Push Drop](./scripts/0048.md) * [Bitcoin Script ASM Format](./scripts/0106.md) +* [Bitcom — Universal Bitcoin Computer: Decentralized Protocol Registry and Composition](./scripts/0300.md) +* [B — Bitcoin Data Protocol](./scripts/0301.md) +* [AIP — Author Identity Protocol](./scripts/0302.md) +* [MAP — Magic Attribute Protocol](./scripts/0303.md) +* [Sigma — Transaction-Bound Script Signatures](./scripts/0304.md) ## Tokens @@ -117,6 +123,11 @@ * [1Sat Provenance Remittance for Basket `1sat`](./tokens/0150.md) * [Latched 1Sat Provenance for Basket `1sat`](./tokens/0156.md) * [Miner-Enforced Resale-Royalty Covenant Tokens (OP_PUSH_TX)](./tokens/0226.md) +* [1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking](./tokens/0306.md) +* [1Sat Ordinals — Inscription Envelopes](./tokens/0307.md) +* [1Sat Ordinal Collections](./tokens/0308.md) +* [BSV-21 Fungible Tokens (JSON / Legacy)](./tokens/0309.md) +* [BSV-21 Fungible Tokens (Binary)](./tokens/0310.md) ## Overlays @@ -166,6 +177,8 @@ * [Fountain-Coded Air-Gap Transport for Arbitrary Payloads](./peer-to-peer/0141.md) * [Universal Handle Addressing and Resolution for the Metanet](./peer-to-peer/0169.md) * [Animated-QR Air-Gap Transport for Arbitrary Payloads (TKQR1)](./peer-to-peer/0225.md) +* [BAP — Bitcoin Attestation Protocol](./peer-to-peer/0311.md) +* [Encrypted Group Messaging over Type-42 Key Derivation](./peer-to-peer/0313.md) ## Key Derivation @@ -189,6 +202,7 @@ * [User Wallet Data Format](./outpoints/0038.md) * [User Wallet Data Format Encryption Extension](./outpoints/0039.md) * [User Wallet Data Synchronization](./outpoints/0040.md) +* [Outpoint Content Addressing](./outpoints/0305.md) ## Opinions diff --git a/apps/0146.md b/apps/0146.md index e8f694c..fab44a2 100644 --- a/apps/0146.md +++ b/apps/0146.md @@ -102,7 +102,7 @@ Where a manifest states at least one condition, admission is self-service: a rea | `ungateBurn` | decimal string | conditional | satoshis to burn to ungate; required while any condition is on | | `successor` | handle | no | who may assume custody after dormancy, per 8.3 | | `dormantAfter` | blocks | no | holder silence after which `successor` may sign, per 8.3 | -| `token` `vouch` `renounce` `quorum` `fee` `roles` | object | no | conditions, per 2.3 | +| `token` `vouch` `renounce` `quorum` `timelock` `fee` `roles` | object | no | conditions, per 2.3 | An absent condition and one present with `"on": false` evaluate identically; the distinction exists for an editor holding a half-configured condition and nowhere else. @@ -372,7 +372,7 @@ A **member** reads the room and posts in it. A **mod** also deletes messages and Banning is strictly downward and never sideways: no role bans its own rank. An admin banning an admin is the one action that can empty a room's admin set in a single click. **Custody is not a rank** — the holder sits underneath the ladder rather than on top of it, may act on any participant, and cannot be acted on; without that, an ungated room where everybody is an admin has nobody able to act on anybody. Deleting a message leaves a record that a message was removed rather than silently closing the gap, since a transcript that rewrites itself is one nobody can reason about afterwards. -A **ban** is recorded as a statement against the handle under BRC-169 section 10.7, scoped to the room — so it has an author, a time and a claim, which a row in a ban array does not. It is **attributed**, reversing BRC-169 section 10.7.1's default: that default protects somebody speaking against a peer at their own risk, and a moderator acting inside a room they moderate is in the opposite position. A room-scoped statement does not contribute to the subject's standing anywhere else and does not satisfy a renounce gate in another room; being unwelcome in one room is not a reputation, and a mechanism letting one moderator's decision follow somebody across the network would be worse than the list it replaced. The subject is told, and by whom, and any role that could impose the ban can lift it. How a ban is then read back as a condition — where the record lives, what scoping means at evaluation time, and what lifting is — is section 4.5. +A **ban** is recorded as a statement against the handle under BRC-169 section 10.7, scoped to the room — so it has an author, a time and a claim, which a row in a ban array does not. It is **attributed**, reversing BRC-169 section 10.7.1's default: that default protects somebody speaking against a peer at their own risk, and a moderator acting inside a room they moderate is in the opposite position. A room-scoped statement does not contribute to the subject's standing anywhere else and does not satisfy a renounce gate in another room; being unwelcome in one room is not a reputation, and a mechanism letting one moderator's decision follow somebody across the network would be worse than the list it replaced. The subject is told, and by whom, and any role that could impose the ban can lift it. How a ban is then read back as a condition — where the record lives, what scoping means at evaluation time, and what lifting is — is section 4.6. Closing a room is a signed statement carrying who closed it and when; conforming clients stop accepting posts and render the room as closed. History remains readable, because section 9 is why nothing here can un-deliver a message, and a client presenting closure as deletion has promised something no client can perform. diff --git a/apps/0218.md b/apps/0218.md index 9be3996..54afbed 100644 --- a/apps/0218.md +++ b/apps/0218.md @@ -444,12 +444,12 @@ This document specifies what a command means, not how it looks, with three excep ### 11. Access Gates -A room may condition **reading** it on facts about the reader — a token they hold, a vouch somebody signed, a statement written against them. That mechanism is specified in [BRC-190](./0190.md), which subsumes and replaces the sketch that previously stood in this section. +A room may condition **reading** it on facts about the reader — a token they hold, a vouch somebody signed, a statement written against them. That mechanism is specified in [BRC-146](./0146.md), which subsumes and replaces the sketch that previously stood in this section. Two boundaries are worth restating here, because both are about this document. -1. Access gates define no verbs and reserve none. Configuring a gate from a conversational interface is a matter for this document; what a gate *is* and how it evaluates is a matter for BRC-190. -2. The `/gate` verb reserved in section 6 is a different thing and remains reserved. It is the **write** half — charging for entry, with custody, refunds, and a rule for what happens when the room ends. BRC-190 specifies the **read** half only. +1. Access gates define no verbs and reserve none. Configuring a gate from a conversational interface is a matter for this document; what a gate *is* and how it evaluates is a matter for BRC-146. +2. The `/gate` verb reserved in section 6 is a different thing and remains reserved. It is the **write** half — charging for entry, with custody, refunds, and a rule for what happens when the room ends. BRC-146 specifies the **read** half only. ## Security Considerations @@ -478,6 +478,6 @@ Two boundaries are worth restating here, because both are about this document. ## References - [BRC-3: Digital Signature Creation and Verification](../wallet/0003.md) -- [BRC-190: Access Gates for Metanet Rooms](./0190.md) +- [BRC-146: Access Gates for Metanet Rooms](./0146.md) - [BRC-169: Universal Handle Addressing and Resolution for the Metanet](../peer-to-peer/0169.md) - [RFC 2119: Key words for use in RFCs to Indicate Requirement Levels](https://www.rfc-editor.org/rfc/rfc2119) diff --git a/apps/0312.md b/apps/0312.md new file mode 100644 index 0000000..a681ef2 --- /dev/null +++ b/apps/0312.md @@ -0,0 +1,169 @@ +# BRC-312: Bitcoin Schema — Social Data Types + +Open Protocol Labs (info@opl.dev) + +**Authors:** Luke Rohenaz (luke@opl.dev) + +**Contributors:** Austin Rappaport (MrZ), Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +Bitcoin Schema is a community-driven collection of extensible data schemas that enable interoperable, data-based applications on Bitcoin SV — inspired by Schema.org's role on the web. This BRC specifies the **social core** of Bitcoin Schema: the composition model (content in B, attributes in MAP, authorship in AIP) and the on-chain record types for social applications — `post`, reply, `repost`, `like`, `unlike`, `follow`, `unfollow`, `friend`, `message`, tags, and attachments. Records written to these schemas can be indexed and queried to build full-featured social platforms whose data is shared across applications. + +Bitcoin Schema also defines further schema families (generic payments, on-chain functions, an on-chain package registry, token schemas); those are out of scope here and may become follow-on BRCs. + +## Motivation + +Interoperability between on-chain applications requires shared vocabulary, not just shared protocols. B ([BRC-301](../scripts/0301.md)) says how to store content, MAP ([BRC-303](../scripts/0303.md)) says how to attach attributes, and AIP ([BRC-302](../scripts/0302.md)) says how to sign — but none of them say that a post is `type post` or that a like names its target with a `tx` key. Bitcoin Schema supplies that layer: a common set of `type` values and key vocabularies so that a post written by one application renders in every other application that speaks the schema. + +The pioneering prior work for on-chain social data is the **Memo protocol** by Jason Chavannes, which first demonstrated posts, replies, likes, follows, topics, and profiles as OP_RETURN records, each action under its own fixed binary prefix. Bitcoin Schema generalizes that action vocabulary onto the composable B / MAP / AIP stack — extensible key/value attributes in a shared namespace instead of fixed per-action prefixes — and the original MAP specification documents this lineage directly, mapping Memo's operations to their MAP equivalents. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Composition Model + +Every Bitcoin Schema social record is a data-carrier output composed with the [BRC-300](../scripts/0300.md) pipeline: + +``` +[B ] | MAP SET app type [ ...] | AIP
+``` + +- **Content** (when the type carries content) is a B segment ([BRC-301](../scripts/0301.md)). +- **Attributes** are a MAP `SET` segment ([BRC-303](../scripts/0303.md)) carrying at minimum `app` (the producing application's name) and `type` (the schema type). +- **Authorship** is an AIP signature ([BRC-302](../scripts/0302.md)) covering the fields to its left. Records SHOULD be AIP-signed; unsigned records have no verifiable author. +- **Identity** references use BAP identity keys ([BRC-311](../peer-to-peer/0311.md)) under the key `bapID`. + +### 2. Type Vocabulary + +This document defines the following `type` values: + +| `type` | Content segment | Purpose | +|--------|-----------------|---------| +| `post` | B (required) | New content published to the network | +| `repost` | none | Amplify an existing post by txid | +| `like` | none | Positive sentiment about a target | +| `unlike` | none | Undo a like | +| `follow` | none | One-way relationship to an identity | +| `unfollow` | none | Remove a follow | +| `friend` | none | Two-way relationship request with key exchange | +| `message` | B (required) | Real-time chat content (separate namespace from `post`) | + +A reply is not a distinct type: it is a `post` with a transaction context (Section 4). + +### 3. Context and Subcontext + +Types MAY carry an optional context for categorization and threading, expressed with a consistent key pattern: the `context` key names **which key** serves as the context, and that named key carries the value. `subcontext` works identically: + +``` +context [subcontext ] +``` + +Examples of the pattern: + +- Reply threading: `context tx tx ` — the context is the `tx` key, whose value is the parent post's txid. +- Channel chat: `context channel channel my-chatroom` +- Private message: `context bapID bapID ` +- Platform integration: `context provider provider youtube subcontext videoID videoID ` — e.g. commenting on a YouTube video. +- Physical products: a UPC code as context for product reviews. + +Context determines rendering and view placement; tags (Section 6) are general-purpose metadata that do not. + +### 4. Content Types + +**Post:** + +``` +B | MAP SET app type post | AIP BITCOIN_ECDSA
+``` + +Content may be plain text, markdown, images, or any media B supports. + +**Reply** — a post whose context is the parent transaction: + +``` +B | MAP SET app type post context tx tx | AIP BITCOIN_ECDSA
+``` + +**Repost** — amplifies existing content without duplicating it; MAY add new context/subcontext, surfacing the original in additional contexts (for example reposting a UPC-context product comment with a `url` context so it appears in web-oriented apps): + +``` +MAP SET app type repost tx | AIP BITCOIN_ECDSA
+``` + +**Message** — like a post but in a separate namespace intended for real-time chat. Global, channel-scoped, and private forms: + +``` +B | MAP SET app type message | AIP ... +B | MAP SET app type message context channel channel | AIP ... +B | MAP SET app type message context bapID bapID | AIP ... +``` + +### 5. Action Types + +**Like / Unlike** — sentiment about a target named by a global identifier key (most commonly `tx`): + +``` +MAP SET app type like tx | AIP BITCOIN_ECDSA
+MAP SET app type unlike tx | AIP BITCOIN_ECDSA
+``` + +**Follow / Unfollow** — one-way relationships between identities: + +``` +MAP SET app type follow bapID | AIP BITCOIN_ECDSA
+MAP SET app type unfollow bapID | AIP BITCOIN_ECDSA
+``` + +**Friend** — a two-way relationship enabling secured communications. The record carries a `publicKey` derived for the friendship: the deriving path is computed from the SHA-256 hash of the counterparty's BAP identity key (via the BAP library's `getSigningPathFromHex`), and the derived public key is published so the counterparty can construct a shared communication channel: + +``` +MAP SET app type friend bapID publicKey | AIP BITCOIN_ECDSA
+``` + +**Action state resolution:** for paired actions from the same identity on the same target (`like`/`unlike`, `follow`/`unfollow`), indexers MUST take the latest action in blockchain order as the current state. + +### 6. Tags + +Tags categorize content for search and filtering, carried as a MAP `ADD` (list semantics, [BRC-303](../scripts/0303.md)) in an additional output of the same transaction: + +``` +MAP ADD tags ... | AIP BITCOIN_ECDSA
+``` + +### 7. Attachments + +Attachments carry rich media alongside a post or message, each as a separate B output ([BRC-301](../scripts/0301.md)) in the same transaction, AIP-signed like any other output: + +``` +output n: B | AIP BITCOIN_ECDSA
+output n+1: B | AIP BITCOIN_ECDSA
+``` + +Any media type is supported: text formats (HTML, CSS, JavaScript, Markdown), images, audio, video, and binary documents. + +### 8. Extensibility + +The schema set is deliberately open: applications MAY define additional keys on any type, and readers MUST ignore keys they do not implement. New types and schema families are added through the community process at bitcoinschema.org. + +## Security Considerations + +- **Unsigned records** — anything can be written under any `app` name and `type`; only the AIP signature binds a record to an author, and only a BAP identity chain ([BRC-311](../peer-to-peer/0311.md)) binds that author to a persistent identity. Indexers SHOULD treat unsigned records as anonymous and unverifiable. +- **Private messages are not encrypted by this schema** — `context bapID` scopes delivery, not confidentiality. Confidential payloads require encryption at the content layer (for example via keys established through the `friend` exchange). +- **Action replay** — the latest-in-block-order rule (Section 5) assumes indexers process reorgs consistently. + +## Implementations + +Bitcoin Schema social types are produced and indexed by multiple production social applications, indexers, and parser libraries in TypeScript and Go. The canonical, community-maintained schema documentation lives at https://bitcoinschema.org. + +## References + +- Bitcoin Schema documentation (canonical): https://bitcoinschema.org/docs +- [BRC-300: Bitcom](../scripts/0300.md) — pipeline composition +- [BRC-301: B — Bitcoin Data Protocol](../scripts/0301.md) — content and attachments +- [BRC-302: AIP — Author Identity Protocol](../scripts/0302.md) — authorship signatures +- [BRC-303: MAP — Magic Attribute Protocol](../scripts/0303.md) — attribute layer (`SET`, `ADD`) +- [BRC-311: BAP — Bitcoin Attestation Protocol](../peer-to-peer/0311.md) — identity keys referenced by `bapID` +- Schema.org (inspiration): https://schema.org +- Memo protocol (Jason Chavannes) — pioneering prior work for on-chain social actions: https://memo.sv/protocol diff --git a/apps/README.md b/apps/README.md index 4e13fca..9a2bbbb 100644 --- a/apps/README.md +++ b/apps/README.md @@ -13,3 +13,4 @@ BRC | Standard 220 | [NotaryHash — Privacy-Preserving Signed-Hash Notarization with SPV-Verifiable Certificates](./0220.md) 224 | [Block Media Format (BMF) — Composable On-Chain Audio/Video](./0224.md) 227 | [Frictionless On-Chain Onboarding via Pre-Funded Claimable Tokens](./0227.md) +312 | [Bitcoin Schema — Social Data Types](./0312.md) diff --git a/outpoints/0305.md b/outpoints/0305.md new file mode 100644 index 0000000..b7d5c7c --- /dev/null +++ b/outpoints/0305.md @@ -0,0 +1,91 @@ +# BRC-305: Outpoint Content Addressing + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +This BRC defines a canonical string form for referencing on-chain content by transaction output — `_` — together with the resolution rule for references that carry no output index, and an optional sequence suffix for content that is updated over time. It exists because the transaction-level addressing used by early data protocols such as B ([BRC-301](../scripts/0301.md)) became under-specified once Bitcoin SV began accepting multiple data-carrier outputs per transaction, and the ecosystem subsequently produced several incompatible disambiguation styles. This document standardizes the convention already deployed across the 1Sat ecosystem. + +## Motivation + +When B and its contemporaries were designed, Bitcoin SV node policy permitted **at most one OP_RETURN output per transaction**, so a bare transaction id unambiguously identified a transaction's data payload. That restriction was a standardness (relay) policy, never a consensus rule, and it was removed in Bitcoin SV node release **v0.2.2.beta (2019-10-30)** — commit `0b8869a93`, "Remove further limits on OP_RETURN data" — which replaced the one-output count check with a cumulative size check against the configurable `-datacarriersize` (default 100KB since v0.2.0). The change became universal on mainnet with the Genesis upgrade's activation at block 620,538 on 2020-02-04. + +From that point on, a transaction may carry data in any number of outputs, and a bare-txid reference no longer identifies a unique payload. Multiple disambiguation styles subsequently appeared in different applications and libraries. A standard is needed so that references written by one system resolve identically in another. Rather than enumerating every historical variant as acceptable, this document standardizes the single form with the widest deployment. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Canonical Outpoint Reference + +A content reference addressing a specific transaction output is written: + +``` +_ +``` + +- `` — 64 lowercase hexadecimal characters: the transaction id in its displayed (hex-string) byte order. +- `_` — a single underscore (`0x5f`). +- `` — the output index as a decimal integer with no leading zeros. + +Example: + +``` +a54d3af24a03bcc28f6b3f2dd0ad249ee042b2f4b95810ae5184ab617a74b8b9_0 +``` + +Producers of new references MUST use this form. The underscore separator is URL-safe, requiring no escaping in URI paths, query strings, or filenames. + +### 2. Bare Transaction References + +A reference consisting of a txid alone remains valid, both for compatibility with references written before multiple data outputs existed and as a deliberate whole-transaction reference. Resolvers MUST resolve a bare-txid reference by scanning the transaction's outputs **in output-index order** and returning the **first output that yields parseable content**. This is the deployed behavior of production gateways; it degenerates to the historical meaning for transactions with a single data output. + +### 3. Legacy Separators (Informative) + +Two other separator conventions exist in deployed code and historical references: + +- `.` — dot-separated, produced by some library outpoint serializations. +- `:` — the traditional Bitcoin Core outpoint notation, unsuitable for URIs because `:` requires escaping. + +Resolvers MAY accept these forms for compatibility with existing references. Producers MUST NOT emit them. + +### 4. Sequence Suffix + +Content protocols that support updating content over time (re-inscription chains and similar update mechanisms, as defined by token protocols such as 1Sat Ordinals, specified separately) use an optional sequence suffix: + +``` +_: +``` + +- `` ≥ 0 — the absolute position in the content's update chain, where `0` is the original content. +- `` = `-1` — the latest version: the resolver follows the chain forward from the referenced outpoint to its most recent state. +- `` = `-2` — the origin's content directly, without forward resolution or merging of later updates. + +A reference with no sequence suffix refers to the content of the referenced output as-is. How a chain is followed (what constitutes the "same" content across spends) is defined by the content protocol, not by this document. + +### 5. Use Within URI Schemes + +Where a URI scheme wraps a content reference — `b://` ([BRC-301](../scripts/0301.md)), ordinals-style `ord://`, or a gateway HTTP path — the reference grammar of this document applies to the reference component. Thus `b://` retains its original transaction-level meaning under the Section 2 resolution rule, and `b://_` addresses a specific output. + +Gateways additionally support directory-style suffixes (`_/path/to/file.css`) for content that encodes a directory structure; that grammar is defined by the serving protocol, not this document. + +### 6. Relationship to Existing Specifications + +This document does not alter the meaning of any existing protocol specification. B ([BRC-301](../scripts/0301.md)) defines `b://`; this document supplies the resolution rule for that form in a multiple-data-output world and the extended form for output-level addressing. Historical chunk-level addressing (referencing an individual push datum within an output script, as practiced by _unwriter's BitFS service with paths of the form `.out..`) is noted for completeness; it saw no adoption beyond that service and is not part of this convention. + +## Implementations + +The `_` form is the production convention across the 1Sat ecosystem — indexers, the ORDFS gateway grammar, and SDK outpoint serialization — and open-source libraries exist that normalize legacy reference styles to it. + +## References + +- [BRC-301: B — Bitcoin Data Protocol](../scripts/0301.md) +- [BRC-37: Spending Instructions Extension](./0037.md) — outpoint-associated wallet metadata +- Bitcoin SV node v0.2.2.beta release notes ("Remove further limits on OP_RETURN data"): https://github.com/bitcoin-sv/bitcoin-sv/releases/tag/v0.2.2.beta +- The policy change commit: https://github.com/bitcoin-sv/bitcoin-sv/commit/0b8869a93037cda7600e7e307e097ae80c9c836e +- Genesis Upgrade specification: https://github.com/bitcoin-sv-specs/protocol/blob/master/updates/genesis-spec.md +- BitFS (archived, historical chunk-level addressing): https://web.archive.org/web/20220926212316/https://bitfs.network diff --git a/outpoints/README.md b/outpoints/README.md index 3de62c4..a9de27d 100644 --- a/outpoints/README.md +++ b/outpoints/README.md @@ -9,3 +9,4 @@ BRC | Standard 38 | [User Wallet Data Format](./0038.md) 39 | [User Wallet Data Format Encryption Extension](./0039.md) 40 | [User Wallet Data Synchronization](./0040.md) +305 | [Outpoint Content Addressing](./0305.md) diff --git a/peer-to-peer/0169.md b/peer-to-peer/0169.md index 83d7dd3..3daa062 100644 --- a/peer-to-peer/0169.md +++ b/peer-to-peer/0169.md @@ -631,7 +631,7 @@ Reassigning a role is a revocation followed by a fresh delegation. Organisation 2. Where it is unattributed, the **claim itself MUST still be shown**. An anonymous count is a rumour with a number on it; an anonymous reason is something the subject can answer and a reader can weigh. 3. A client MUST NOT let a negative statement contribute to any indication that an identity is unverified, exactly as rule 6 forbids the positive case. Both are opinions about a person; verification is arithmetic about a key. 4. Attributed and unattributed statements MUST be visually distinguishable, and a client MUST NOT imply that an unattributed one is attributable on request when it is not. -8. **Attestations MUST be discoverable, not merely publishable.** Rules 3 to 7 say how a peer statement is made and what it means, and say nothing about how a third party finds the statements made *about* a handle. That is the half a relying party actually needs: a client asking "who has vouched for this identity" has no endpoint to ask. An ecosystem SHOULD answer that question for its own handles, at the resolution endpoint of section 5.7, as a list of attestation outpoints with their certifiers. Until an ecosystem does, any mechanism built on this section — including the access gates of [BRC-190](../apps/0190.md) — can be evaluated only by a party that already holds the attestations, which is to say by nobody who needed to ask. +8. **Attestations MUST be discoverable, not merely publishable.** Rules 3 to 7 say how a peer statement is made and what it means, and say nothing about how a third party finds the statements made *about* a handle. That is the half a relying party actually needs: a client asking "who has vouched for this identity" has no endpoint to ask. An ecosystem SHOULD answer that question for its own handles, at the resolution endpoint of section 5.7, as a list of attestation outpoints with their certifiers. Until an ecosystem does, any mechanism built on this section — including the access gates of [BRC-146](../apps/0146.md) — can be evaluated only by a party that already holds the attestations, which is to say by nobody who needed to ask. 9. Because organisations resolve identically to users, the address book doubles as a business directory. ## Security Considerations @@ -695,7 +695,7 @@ Reassigning a role is a revocation followed by a fresh delegation. Organisation - [BRC-104: HTTP Transport for BRC-103 Mutual Authentication](./0104.md) - [BRC-105: HTTP Service Monetization Framework](../payments/0105.md) - [BRC-125: PeerPay URI Scheme for BRC-29 Payments](../payments/0125.md) -- [BRC-190: Access Gates for Metanet Rooms](../apps/0190.md) +- [BRC-146: Access Gates for Metanet Rooms](../apps/0146.md) - [BRC-218: Chat-Native Command Grammar for the Metanet](../apps/0218.md) - [WhatsOnChain Exchange Rate API](https://docs.whatsonchain.com/exchange-rate) - [RFC 1123: Requirements for Internet Hosts](https://www.rfc-editor.org/rfc/rfc1123) diff --git a/peer-to-peer/0311.md b/peer-to-peer/0311.md new file mode 100644 index 0000000..de3ab76 --- /dev/null +++ b/peer-to-peer/0311.md @@ -0,0 +1,233 @@ +# BRC-311: BAP — Bitcoin Attestation Protocol + +Open Protocol Labs (info@opl.dev) + +**Authors:** Siggi (original author) + +**Contributors:** Attila Aros — thanked in the original specification; Luke Rohenaz (luke@opl.dev), Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +The Bitcoin Attestation Protocol (BAP) is a protocol for creating on-chain identities and making generic, privacy-preserving attestations about data without publishing the data itself. A BAP identity is a stable **identity key** linked to a rotatable chain of Bitcoin signing addresses via on-chain `ID` transactions. Attestations reference data as salted, hashed URNs, so third parties (banks, KYC providers, services) can attest to identity attributes — and users can prove them — while revealing nothing else. BAP transactions are Bitcom-style OP_RETURN payloads under the prefix `1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT` ([BRC-300](../scripts/0300.md)), signed with AIP ([BRC-302](../scripts/0302.md)). + +This document specifies the core protocol: the transaction format, the `ID`, `ATTEST`, `ALIAS`, `DATA`, and `REVOKE` operations, URN construction, identity key derivation, key rotation, sequence rules, and the attestation patterns built on them (delegation, power of attorney, blacklisting, assertions, consent grants, and the uniKey). + +## Motivation + +BAP's design goals: + +1. A simple protocol for generic attestation of data, without the need to publish the data itself. +2. Decouple signing with an address from the funding source address — no on-chain transactions are required from the signing identity address. +3. Allow rotation of signing keys without changing existing attestations. +4. Allow creation of an infinite number of identities, while still allowing attested attributes to be proven across identities. + +BAP was inspired by the Author Identity Protocol ([BRC-302](../scripts/0302.md)), which provides the signature layer, and extends it with stable identities, key rotation, and an attestation vocabulary. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Transaction Format + +BAP uses the Bitcom convention ([BRC-300](../scripts/0300.md)) with the protocol prefix `1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT`, signed with AIP ([BRC-302](../scripts/0302.md)): + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +[ID | ATTEST | ALIAS | DATA | REVOKE] +[ID Key | URN Attestation Hash] +[Sequence | Address | Data] +| +15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva +[AIP Signing Algorithm] +[AIP Signing Address] +[AIP Signature] +``` + +By default all fields are signed, so AIP's optional field indexes are omitted. + +- The third field carries the identity key (`ID`, `ALIAS`) or the URN attestation hash (`ATTEST`, `DATA`, `REVOKE`). +- The fourth field carries the Bitcoin signing address in `ID` transactions, the **Sequence** in `ATTEST`/`REVOKE` transactions, and the payload in `ALIAS`/`DATA` transactions. +- The **Sequence** is a monotonically increasing integer preventing replay across attestation and revocation: for a given attestation hash and signatory, the transaction with the highest sequence is the current state. + +### 2. URNs + +BAP carries attestation data as w3c-style Uniform Resource Names: + +``` +urn:[namespace identifier]:[...URN] +``` + +The URN itself is never published; it is hashed with SHA-256 when used in a transaction. Defined URN schemes: + +| Scheme | Form | +|--------|------| +| Identity attribute | `urn:bap:id:[Attribute name]:[Attribute value]:[Nonce]` | +| Attestation | `urn:bap:attest:[Attribute hash]:[Identity key]` | +| Delegation | `urn:bap:delegate:[from idKey]:[to idKey]:[Nonce]` | +| Power of attorney | `urn:bap:poa:[PoA attribute]:[Address]:[Nonce]` | +| Blacklist | `urn:bap:blacklist:[type]:[attribute]:[key]` | +| Assertion | `urn:bap:assert:[assertion text]:[Nonce]` | +| Consent grant | `urn:bap:grant:[Attribute names]:[Identity key]` | + +The **Nonce** is a unique random string providing entropy so that hashing the URN cannot collide and is not vulnerable to dictionary attacks. Nonces MUST NOT be reused across identities; create a new random nonce for each attribute. + +Attribute names SHOULD be drawn from https://schema.org — in particular https://schema.org/Person for personal attributes and https://schema.org/Organization for organizations. + +### 3. Identity Creation and Key Rotation (`ID`) + +An identity links a stable **identity key** to a chain of Bitcoin signing addresses. Two keys are created (recommended: derived from an HD private key with known derivations): a **root address** and a **first signing address**. + +The identity key is computed from the root address (fed to the hash functions as binary, not string): + +``` +identityKey = base58( ripemd160 ( sha256 ( rootAddress ) ) ) +``` + +This binds the identity key to the root address, preventing others from claiming the same identity key. (Older identities used random identity keys; they remain valid, but new identities MUST derive as above.) + +The identity is established with an `ID` transaction linking the identity key to the first signing address, signed by the **root address**: + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +ID +3SyWUZXvhidNcEHbAC3HkBnKoD2Q // identity key +1K4c6YXR1ixNLAqrL8nx5HUQAPKbACTwDo // new signing address +| +15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva +BITCOIN_ECDSA +1WffojxvgpQBmUTigoss7VUdfN45JiiRK // root address signs + +``` + +**Rotation:** to rotate to a new signing key, publish a new `ID` transaction naming the new address, signed by the **previous** signing address. Each signing key in the chain is immutably recorded; signatures for the identity are made with the active key at that time. + +**Destruction:** to destroy the identity (for example after compromise of the latest key), publish an `ID` transaction with address field `0`, signed by the **root address**. The root address is reserved for this purpose and SHOULD NOT be used anywhere else. + +### 4. Attestation (`ATTEST`) + +Anyone can attest to any identity's attribute by hashing and signing. For an identity attribute URN: + +1. Hash the attribute URN: `attributeHash = sha256(urn:bap:id:name:John Doe:)`. +2. Construct the attestation URN: `urn:bap:attest::`. +3. Hash the attestation URN: `attestationHash = sha256(...)`. +4. Publish, signed by the attester's active signing key: + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +ATTEST + +0 // sequence +| +15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva +BITCOIN_ECDSA + + +``` + +Because the attestation hash is deterministic, every authority attesting the same attribute publishes the same third field — so all attestations of an attribute can be found with one indexed query, and a verifier selects the attester it trusts. + +**Verification flow:** a user proves an attested attribute by sharing their identity key and the full attribute URN, and signing a challenge from the verifier with their active key. The verifier checks: (a) the challenge signature proves control of the active address; (b) an `ID` chain links that address to the identity key; (c) the attestation URN is signed by the (current) address of a trusted authority. Nothing beyond the shared attribute is revealed. + +### 5. Attestation Applications + +All of the following are ordinary `ATTEST` transactions over different URN schemes: + +- **Delegation** — `urn:bap:delegate:::`, signed by the *delegating* identity, links attributes verified on one identity (e.g. a KYC'd identity) to another. Challenges involving a delegated identity MUST be signed by **both** identities. The primary (KYC'd) identity SHOULD never be used directly in applications; create a fresh identity per application. +- **Power of attorney** — `urn:bap:poa::
:` with defined attributes `real-estate`, `business`, `finance`, `family`, `general`. Real-world authority only; revocable via `REVOKE`. +- **Blacklisting** — `urn:bap:blacklist:bitcoin:tx-id:`, `urn:bap:blacklist:bitcoin:address:
`, or `urn:bap:blacklist:ip-address::` (the idKey salt prevents bulk reverse lookups of personally identifiable IP data). Deliberately one-way: it is easy to check whether a service blacklisted a given item, hard to enumerate a service's blacklist — and blacklist attestations are indistinguishable from any other attestation. +- **Assertions** — `urn:bap:assert::`, e.g. asserting ownership of a file by its SHA-256 hash. +- **Consent grants** — `urn:bap:grant::` records that a user freely granted a service access to data; revoking the grant (`REVOKE`) signals the service must delete its copies. Services SHOULD monitor for revocations. + +### 6. Publishing Identity Information (`ALIAS`) + +`ALIAS` publicly binds an identity key to a real-world entity. The data field is a stringified JSON object using schema.org attributes: + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +ALIAS + +{"@type":"Organization","name":"Banco De Bitcoin", ...} +| + +``` + +ALIAS is RECOMMENDED only for organizations that want a public identity; ordinary users SHOULD NOT publish an alias. + +### 7. Publishing Data (`DATA`) + +`DATA` attaches data to an attestation, optionally encrypted so only sender and receiver can read it: + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +DATA + + +| + +``` + +- The signing identity MUST match the identity of the referenced attestation; otherwise the data MUST be ignored. +- `DATA` MAY be piped in the same output as its `ATTEST` (two BAP segments followed by one AIP signature). +- Encryption uses ECIES, specifically the electrum-ecies traditional two-key mode: encrypted with the attester's private key and the identity owner's public key. + +### 8. Revocation (`REVOKE`) + +A `REVOKE` transaction has exactly the format of the `ATTEST` it revokes, with the `REVOKE` keyword and a **higher sequence number**: + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +REVOKE + +1 // sequence, higher than the ATTEST +| + +``` + +For a given attestation hash and signatory, the highest-sequence transaction wins; the sequence prevents replaying an earlier `ATTEST` to undo a revocation. + +### 9. uniKey + +The uniKey is a unique, service-portable hash of a person's KYC attributes: + +``` +privateUniKey = sha256( fullName ‖ nationality ‖ birthDate ‖ socialSecurityNr ‖ + passportNr ‖ passportExpirationDate ‖ base64(passport image) ) +uniKey = sha256( privateUniKey ) +``` + +The privateUniKey SHOULD be derived only from a digital (NFC) passport supporting all listed attributes; the passport image bytes supply the entropy that guards against dictionary attacks. The privateUniKey MUST never be shared; the uniKey is shared only where full KYC would otherwise be. `uniKeyExpirationDate` equals the passport expiration, and its attribute URN uses the uniKey itself as the nonce, linking the two verifiably: + +``` +urn:bap:id:uniKey:: +urn:bap:id:uniKeyExpirationDate:: +``` + +### 10. Key Derivation Modes (Informative) + +Current implementations support both BIP32 (HD) derivation (legacy) and BRC-42-style "Type 42" derivation (modern) for managing root and signing keys, with a migration path between them. The on-chain protocol is identical in both modes. + +### 11. Provisional Extensions (Not Specified Here) + +The upstream protocol document sketches BAP-on-Metanet and a `did:bap:` w3c DID method; both are explicitly marked PROVISIONAL and incomplete there, and are not part of this specification. They may become follow-on BRCs when finalized. + +## Security Considerations + +- **Root key hygiene** — the root address is the identity's destruction credential; it SHOULD be kept offline and never reused. +- **Nonce reuse** — reusing attribute nonces across identities links those identities and weakens dictionary-attack resistance. +- **Attester trust** — an attestation proves that a specific signatory signed a hash, nothing more; verifiers choose which attesters to trust. +- **Sequence handling** — indexers MUST apply the highest-sequence rule per (attestation hash, signatory) or revocations can be silently ignored. + +## Implementations + +BAP has production implementations in TypeScript and Go, a CLI, an overlay indexer, and is the identity layer for Sigma-based authentication systems and multiple BSV wallets. The canonical protocol specification is maintained at https://github.com/BitcoinSchema/bap (`PROTOCOL.md`). + +## References + +- BAP protocol specification (canonical): https://github.com/BitcoinSchema/bap/blob/master/PROTOCOL.md +- Original repository (historical): https://github.com/icellan/bap +- [BRC-300: Bitcom](../scripts/0300.md) — prefix and pipeline conventions +- [BRC-302: AIP — Author Identity Protocol](../scripts/0302.md) — signature layer +- [BRC-42: BSV Key Derivation Scheme](../key-derivation/0042.md) — modern key derivation mode +- schema.org Person / Organization attribute vocabularies: https://schema.org/Person, https://schema.org/Organization +- w3c URI/URN clarification: https://www.w3.org/TR/uri-clarification/ +- electrum-ecies (DATA encryption): https://www.npmjs.com/package/electrum-ecies diff --git a/peer-to-peer/0313.md b/peer-to-peer/0313.md new file mode 100644 index 0000000..ff84789 --- /dev/null +++ b/peer-to-peer/0313.md @@ -0,0 +1,266 @@ +# BRC-313: Encrypted Group Messaging over Type-42 Key Derivation + +Open Protocol Labs (info@opl.dev) + +**Authors:** Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +This BRC specifies end-to-end encrypted group messaging for BSV applications, built entirely on cryptographic primitives already native to the ecosystem: secp256k1 keys, ECDH, ECDSA, and [BRC-42](../key-derivation/0042.md)/[BRC-43](../key-derivation/0043.md) key derivation. Two profiles are defined. **Profile A (pairwise fan-out)** encrypts each group message once per member over existing [BRC-78](./0078.md) pairwise channels — the required baseline, suitable for small groups. **Profile B (sender keys)** adopts the hash-ratchet construction fielded by WhatsApp, Signal groups, and Matrix Megolm, re-parameterized onto secp256k1: each member distributes a per-session ratchet state and signing key once over pairwise channels, then encrypts each message exactly once for the whole group. + +The specification deliberately introduces no novel cryptography: every construction is a documented, fielded pattern. It composes with the existing stack — [BRC-78](./0078.md) pairwise encryption, [BRC-33](./0033.md) messagebox transport, [BRC-169](./0169.md) envelopes and reachability, and optionally [BRC-146](../apps/0146.md) room membership — and supplies the one capability that stack explicitly delegates: keying a room's contents so that non-members cannot decrypt them. + +## Motivation + +The BSV messaging stack answers who may *deliver* to an identity (BRC-169 §8 scopes and tolls, enforced at the messagebox) and what a conforming client *renders* (BRC-146 access gates), and BRC-146 §9 is explicit that neither is confidentiality: "A room whose confidentiality matters must key its contents so that non-holders cannot decrypt them; that mechanism is out of scope here." BRC-78 provides real encryption but is strictly two-party: one sender, one recipient, `anyone` prohibited, no shared-key mechanism of any kind. + +No fielded BSV application currently implements encrypted group chat; the deployed direct-message ciphers additionally lack forward secrecy entirely (static keys derived from static identity keys). This document fills that gap with the industry-standard design, stated honestly: sender-key groups provide partial forward secrecy and require explicit rekeying on membership change, and this document says exactly what is and is not achieved. + +## Specification + +The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" are to be interpreted as described in RFC 2119. + +### 1. Layering and Prerequisites + +| Layer | Provided by | This document's use | +|---|---|---| +| Identity | secp256k1 identity keys; optionally BAP ([BRC-311](./0311.md)) | Members are identified by compressed identity public keys | +| Pairwise channels | [BRC-78](./0078.md) portable encrypted messages over [BRC-42](../key-derivation/0042.md)/[BRC-43](../key-derivation/0043.md) | Carries all control messages (Section 6) | +| Transport | [BRC-33](./0033.md) messageboxes; [BRC-169](./0169.md) §7 envelopes | Off-chain delivery of control and group messages (Section 8) | +| Membership authority (optional) | [BRC-146](../apps/0146.md) rooms | Qualification, roles, bans, and rekey triggers (Section 9) | + +A pairwise channel between two members exists when each can address the other under BRC-78. Applications using the Bitcoin Schema social graph establish this with the on-chain `friend` exchange ([BRC-312](../apps/0312.md)); the mechanism of introduction is out of scope here — this document requires only that a pairwise BRC-78 channel exists between the inviter and the invitee. + +All multi-byte integers in this document are big-endian unless stated otherwise. All public keys are 33-byte compressed secp256k1 points. "Identity signature" means an ECDSA signature by a member's identity private key, encoded as a 64-byte compact signature `r ‖ s` with low-S normalization, over the SHA-256 of the stated bytes. + +### 2. Groups, Sessions, and Members + +- A **group** is an ordered-by-nobody set of member identity keys sharing a conversation. A group is identified by a **group ID**: 16 cryptographically random bytes, generated by the creator. A group MAY additionally be bound to a BRC-146 room (Section 9); the group ID remains the cryptographic identifier. +- A **member** is an identity key currently entitled to hold the group's key material. +- Under Profile B, each member maintains one **outbound session** per group: a ratchet state plus a session signing keypair. Each member holds one **inbound session** per (group, other member) pair, received via control messages. A **session ID** is 16 cryptographically random bytes generated by the session's owner. +- The **creator** of a group is its initial administrator. For standalone groups (no BRC-146 binding), administration semantics are defined in Section 7; for room-bound groups, Section 9 defers roles to BRC-146. + +### 3. Profile A — Pairwise Fan-Out (REQUIRED) + +Every conforming implementation MUST support Profile A. To send a group message under Profile A, the sender encrypts the message payload (Section 5.4's plaintext framing) separately to each other member as a BRC-78 portable encrypted message, and delivers each per Section 8. + +Profile A has per-message cost linear in group size, and membership change requires no rekey: members simply start or stop being addressed. Implementations SHOULD use Profile A for small groups and MUST use it as the fallback whenever a Profile B session is unavailable for a recipient. + +Forward secrecy note: Profile A inherits BRC-78's key schedule — a fresh random 256-bit key ID per message yields per-message derived keys, but all derivations stem from static identity keys, so compromise of an identity key compromises past traffic. Profile A trades scalability and forward-secrecy hygiene for maximum simplicity. + +### 4. Profile B — Sender Keys (RECOMMENDED) + +Profile B adopts the Megolm session-ratchet design (Apache-2.0 specification by the Matrix.org team), with two deliberate departures stated here once: the payload AEAD is **AES-256-GCM** (aligning with BRC-78's ecosystem-wide cipher choice) rather than Megolm's AES-256-CBC with truncated HMAC, and the signing algorithm is **secp256k1 ECDSA** rather than Ed25519. The ratchet mathematics are unchanged. + +#### 4.1 Session State + +An outbound session consists of: + +- A **ratchet state** `R_i`: four 32-byte parts `R_{i,0}, R_{i,1}, R_{i,2}, R_{i,3}` (128 bytes total), initialized from a cryptographically secure random source, with a 32-bit counter `i` starting at 0. +- A **session signing keypair**: a fresh, random secp256k1 keypair generated for this session, used for nothing else. It is bound to the member's identity by the identity signature on the session-share control message (Section 6.1), not by derivation. + +#### 4.2 Ratchet Advancement + +Define, for `j` in 0..3: + +``` +H_j(A) = HMAC-SHA-256(key = A, message = byte(j)) +``` + +where `byte(j)` is the single byte `0x00`, `0x01`, `0x02`, or `0x03`. Advancing from `i` to `i+1`: + +- `R_{i,3}` advances every step: `R_{i+1,3} = H_3(R_{i,3})`, except at the boundaries below. +- Every `2^8` steps (when `i+1 ≡ 0 mod 2^8`), part 2 reseeds: `R_{i+1,2} = H_2(R_{i,2})` and `R_{i+1,3} = H_3(R_{i,2})`. +- Every `2^16` steps, part 1 reseeds and cascades: `R_{i+1,1} = H_1(R_{i,1})`, `R_{i+1,2} = H_2(R_{i,1})`, `R_{i+1,3} = H_3(R_{i,1})`. +- Every `2^24` steps, part 0 reseeds and cascades: `R_{i+1,0} = H_0(R_{i,0})`, `R_{i+1,1} = H_1(R_{i,0})`, `R_{i+1,2} = H_2(R_{i,0})`, `R_{i+1,3} = H_3(R_{i,0})`. + +The ratchet is one-way: earlier states cannot be computed from later ones. Winding forward from any state to any later index requires at most 1020 hash computations. A receiver holding `R_i` MUST advance (never rewind) to decrypt messages at indices `≥ i` and cannot decrypt indices `< i`. + +#### 4.3 Message Key Derivation + +For message index `i`: + +``` +KEY_i ‖ IV_i = HKDF-SHA-256(salt = 32 zero bytes, IKM = R_i (128 bytes), + info = "bsv group message keys", L = 44) +``` + +per RFC 5869, yielding a 32-byte AES-256 key and a 12-byte GCM IV. Because each ratchet index is used for exactly one encryption (Section 4.5), the derived deterministic IV never repeats under a given key; implementations MUST NOT encrypt twice at the same index. + +#### 4.4 Group Message Format + +``` +| Field | Length | Description | +|-------------|----------|----------------------------------------------------| +| Version | 4 bytes | 0x47525031 ("GRP1") | +| Group ID | 16 bytes | The group this message belongs to | +| Session ID | 16 bytes | The sender's outbound session | +| Index | 4 bytes | Ratchet index i (unsigned, big-endian) | +| Ciphertext | Variable | AES-256-GCM over the plaintext framing, using KEY_i and IV_i; the 16-byte GCM tag is appended by the AEAD | +| Signature | 64 bytes | ECDSA (compact, low-S) by the session signing key, over SHA-256 of all preceding bytes | +``` + +Verification order: a receiver MUST verify the signature against the signing public key from the stored inbound session for (Group ID, Session ID), check replay (Section 4.6), wind the ratchet to `i`, then decrypt. A message referencing an unknown session is held until the corresponding session-share arrives or discarded per application policy; it MUST NOT be treated as authenticated. + +#### 4.5 Sending + +To send: advance the outbound ratchet to the next unused index, derive `KEY_i`/`IV_i`, encrypt the plaintext framing (Section 5.4), construct the message, sign it with the session signing key, and deliver the identical bytes to every member (Section 8). The per-message cost is one encryption regardless of group size. + +#### 4.6 Replay Protection and Ordering + +Receivers MUST track, per inbound session, the set of indices already accepted, and MUST reject a message whose (Session ID, Index) pair has been seen. The index provides per-sender ordering; this document provides no cross-sender ordering, and applications requiring a total order must impose one at the application layer (Section 10, non-goals). + +#### 4.7 Session Lifetime and Rotation + +- A session MUST NOT exceed index `2^32 - 1`. +- A sender SHOULD rotate (create a fresh session and distribute it) after at most `2^16` messages or seven days, whichever comes first, limiting the exposure window of any compromised ratchet state. +- Receivers SHOULD discard ratchet states below the lowest index they still need, converting partial forward secrecy into practiced forward secrecy. + +### 5. Control and Content Framing + +All control messages travel over pairwise BRC-78 channels. To distinguish group traffic at the derivation layer, the BRC-78 wrapping for control messages uses the BRC-43 invoice number: + +``` +2-group messaging- +``` + +security level 2 (per-counterparty permission grant), protocol ID `group messaging` (conforming to BRC-43 normalization: lowercase, 5–280 characters, not ending in " protocol"), and a randomly generated 256-bit key ID in base64, exactly as BRC-78 does for `message encryption`. Everything else about the BRC-78 construction (child-key ECDH, AES-256-GCM, wire serialization) is unchanged. + +Within the decrypted BRC-78 content, a one-byte **frame type** discriminates: + +| Type | Meaning | +|------|---------| +| 0x01 | Session share (6.1) | +| 0x02 | Membership change announcement (6.2) | +| 0x03 | Group metadata (6.3) | +| 0x10 | Profile A group content (Section 3) | + +Unknown frame types MUST be ignored. + +#### 5.4 Plaintext Framing (Content Messages) + +The plaintext encrypted by either profile is: + +``` +| Field | Length | Description | +|--------------|----------|-----------------------------------------------| +| Content type | 1 byte | 0x01 = UTF-8 text; 0x02 = Bitcoin Schema record bytes; 0x03 = binary attachment; others reserved | +| Body | Variable | The message content | +``` + +Content type `0x02` carries a serialized Bitcoin Schema ([BRC-312](../apps/0312.md)) record, letting applications reuse the social vocabulary (message types, reactions) inside encrypted groups without inventing a parallel one. + +### 6. Control Messages + +#### 6.1 Session Share (0x01) + +Distributed pairwise to every member when a session is created or rotated, and to a newly added member on join: + +``` +| Field | Length | Description | +|---------------------|-----------|----------------------------------------------| +| Frame type | 1 byte | 0x01 | +| Group ID | 16 bytes | — | +| Session ID | 16 bytes | — | +| Index | 4 bytes | The ratchet index at which sharing begins | +| Ratchet state | 128 bytes | R_{i,0} ‖ R_{i,1} ‖ R_{i,2} ‖ R_{i,3} | +| Signing public key | 33 bytes | The session's signing key | +| Identity signature | 64 bytes | By the sharer's identity key, over SHA-256 of all preceding bytes | +``` + +The identity signature binds the session (and its signing key) to the sharing member's identity; receivers MUST verify it against the sender's identity key before storing the inbound session. Because the shared state is `R_i` at the current index, a newly added member can decrypt from the join point forward and nothing earlier — member addition requires no rekey. + +#### 6.2 Membership Change (0x02) + +``` +| Field | Length | Description | +|--------------------|----------|-------------------------------------------| +| Frame type | 1 byte | 0x02 | +| Group ID | 16 bytes | — | +| Change | 1 byte | 0x01 add, 0x02 remove | +| Member | 33 bytes | Identity key of the affected member | +| Identity signature | 64 bytes | By an authorized member (Section 7/9), over SHA-256 of all preceding bytes | +``` + +**Rekey on removal is mandatory.** Upon accepting a remove (or a BRC-146 ban or exclusion, Section 9), every remaining member MUST discard the removed member's inbound sessions, MUST create a fresh outbound session, and MUST distribute it pairwise to the remaining members only. Until a member has rekeyed, its subsequent messages remain readable by the removed member; clients SHOULD rekey before their next send and MUST rekey within seven days. A full rekey is O(n²) pairwise messages across the group; this is the accepted cost of the sender-keys design (Section 11). + +#### 6.3 Group Metadata (0x03) + +An application-defined payload (name, avatar reference, topic), signed by an authorized member. Its schema is out of scope; the frame exists so metadata travels encrypted rather than as messagebox-visible envelope fields. + +### 7. Standalone Group Administration + +For groups not bound to a BRC-146 room: + +- The creator is the initial administrator. Administrators MAY add and remove members and MAY designate additional administrators via membership-change frames (change `0x03` add-admin, `0x04` remove-admin, same layout as 6.2). +- Any member MAY send content. Members learn the roster from add/remove frames; a client MUST accept membership changes only when the identity signature is by a current administrator. +- Two administrators removing each other concurrently is resolved by accepting the change whose carrying message was received first at each client; this document does not provide consensus on the roster, and applications requiring stronger membership agreement should bind the group to a BRC-146 room. + +### 8. Transport Mapping + +- **BRC-33 / BRC-169 messageboxes are the normative transport.** A group or control message is delivered to each member as one BRC-169 §7.2 envelope whose `content` member carries: for control messages and Profile A, the BRC-78 blob; for Profile B group messages, the Section 4.4 message bytes. The envelope's own rules (signature over canonicalized metadata excluding content, scope and toll enforcement at the recipient's messagebox) apply unchanged; nothing in this document extends §7.2. Group traffic is indistinguishable from ordinary encrypted traffic at the messagebox except by pattern. +- Fan-out under a `toll` scope means one toll payment per member envelope, each with its own single-use quote, per BRC-169 §8.3. +- **On-chain anchoring is OPTIONAL and minimal.** The pairwise-channel prerequisite (e.g. the BRC-312 `friend` exchange) is on-chain by that protocol's own design. This document defines no on-chain group record: publishing membership on-chain makes the membership graph public forever, and the roster is already carried encrypted by Section 6. Applications wanting a durable public anchor for group existence MAY publish one (for example a Bitcoin Schema record naming only the group ID) and should weigh the permanence of that disclosure; room-bound groups get their public identity from the BRC-146 room instead. + +### 9. Composition with BRC-146 Rooms + +A group MAY be bound at creation to a BRC-146 room by including the room identifier (`room:/`) in the group metadata frame. For a room-bound group: + +1. **Qualification gates invitation.** A member MUST NOT send a session share to an identity whose current gate verdict is not `qualifies`. (A verdict of `indeterminate` is not `qualifies`.) +2. **Roles govern administration.** BRC-146 condition-derived roles replace Section 7: mods and admins are the authorized signers for membership changes, and the room holder's custody powers are as BRC-146 defines them. +3. **A ban is an immediate removal.** BRC-146 evaluates bans first and immediately; on observing a ban, remaining members MUST treat it as a Section 6.2 removal — discard sessions, rekey now. +4. **Rule-change exclusion rekeys at `effectiveFrom`.** BRC-146 §2.4 requires a manifest change that newly excludes a current participant to carry an `effectiveFrom` at least 1,008 blocks out, with the old manifest deciding until then. The cryptographic rekey binds to when exclusion takes *effect*, not when it is announced: members MUST rekey (excluding the affected participant) when the chain reaches `effectiveFrom`, and MUST NOT rekey earlier on account of the pending change — the participant remains a member, and a decryption capability removed early would contradict the manifest that still decides. The notice period is thereby preserved intact, and the tension between the week of notice and immediate rekey-on-remove dissolves: immediacy applies to bans and explicit removals, `effectiveFrom` to rule changes. +5. **Lapsing is not retroactive** (BRC-146 §6): a participant who lapses and later requalifies missed the sessions rotated in between; they rejoin by receiving fresh session shares like any added member. + +BRC-146's own caveat is inherited: vouch and quorum gates depend on attestation discovery that BRC-169 §10.8 asks ecosystems to serve but none yet does; a v1 room-bound group SHOULD gate on conditions evaluable today (holding, timelock, renounce) or accept `indeterminate` verdicts as non-qualifying. + +### 10. Non-Goals + +The following are explicitly out of scope for this version: post-compromise security beyond session rotation (see Section 11); transcript consistency and total message ordering; metadata privacy (BRC-169's Security Considerations apply in full — the messagebox operator sees who contacts whom, and group fan-out patterns are visible traffic analysis); multi-device synchronization and history storage (BRC-33 deletes on acknowledgment; history is the client's concern and nothing here precludes a client-side store); public channels (unencrypted; covered by BRC-312 `message` with `context channel`); stranger invitations (invitation requires an existing pairwise channel); zero-knowledge private group state; and post-quantum security. + +### 11. Security Considerations + +This section states the construction's known limits plainly; a client or product description that claims more than the following is wrong. + +- **Partial forward secrecy.** Compromise of a stored ratchet state at index `i` exposes all messages of that session from `i` onward — and none before `i`. Mitigations: session rotation (4.7) bounds the window; receivers discarding consumed ratchet states (4.7) protect already-read history. +- **No post-compromise security.** An adversary who obtains a sender key can passively read that sender's session indefinitely until rotation; the hash ratchet never self-heals. This is a documented property of the sender-keys design (Megolm "Limitations"; RFC 9420 §1; Balbás–Collins–Gajland, ASIACRYPT 2023). Rotation and rekey-on-remove are the only remedies, and this document mandates both. +- **Rekey is O(n²) and mandatory on removal.** Until every member rekeys, a removed member reads the non-rekeyed senders. The seven-day bound in 6.2 is a ceiling, not a target. +- **Replay.** Without the 4.6 index tracking, any observer of ciphertext can replay old messages; tracking is therefore REQUIRED, not advisory. +- **The pairwise channel is load-bearing.** Session shares inherit every weakness of the channel that carries them, including unknown-key-share ambiguities; the identity signature inside the share (6.1) is the defense this document adds, and receivers who skip its verification void the group's authenticity entirely. Note that BRC-78's AEAD alone provides no third-party-attributable sender authentication — both parties can compute the key — which is precisely why control frames carry identity signatures. +- **No transcript consistency.** Nothing guarantees all members saw the same messages; per-sender indices guarantee only per-sender gap detection. +- **No deniability claim.** Content messages are signed by session keys (linkable to identities via signed session shares held by members); this document makes no off-the-record claim. +- **Forward secrecy of the fielded stack.** Neither BRC-78 nor the deployed legacy ciphers ratchet; this document's Profile B is the first forward-secrecy mechanism in the stack, and Profile A explicitly does not improve on BRC-78's static-key exposure. +- **secp256k1 ECDH implementation note.** Deriving shared secrets on secp256k1 has a known footgun: some libraries hash the ECDH output by default while others return the raw x-coordinate. BRC-42's shared secret is the ECDH point per that specification and its test vectors; implementations MUST validate against the BRC-42 vectors rather than assuming their library's default (compare the analogous warning in Nostr NIP-44, which specifies the unhashed x-coordinate and warns against libsecp256k1's hashing default). +- **Legacy cohort.** Deployed applications carrying Electrum-ECIES ("BIE1", AES-128-CBC, deterministic KDF-derived IV) direct messages and BIP32-path friend keys are a distinct legacy cohort. This document does not accept those constructions: new group and pairwise traffic under this specification uses BRC-42/43/78 exclusively, and clients supporting legacy history SHOULD treat it as read-only. + +### 12. Future Work + +- **MLS (RFC 9420) migration** following the Marmot precedent from the Nostr ecosystem: standard-ciphersuite MLS with separate per-group keys, the secp256k1 identity key binding identity via the MLS credential — sidestepping the absence of a standardized secp256k1 ciphersuite. TreeKEM would replace this document's O(n²) rekey with O(log n) and add true post-compromise security. +- **DHKEM-secp256k1** (CFRG draft-wahby-cfrg-hpke-kem-secp256k1) as the path to a native ciphersuite. +- **Schnorr (BIP340) signatures** for session and identity signatures as ecosystem tooling adopts them. +- Post-quantum hybrid ratchets (Signal Double Ratchet revision 4's documented variants). +- Ratcheted 1:1 channels (a ported Double Ratchet as a BRC-78 successor), which this document's Profile A would inherit automatically. +- Broadcast channels (owner-published feeds) — a different threat model, likely a sibling BRC. +- Metadata privacy (sealed-sender analogs over BRC-33). + +## Implementations + +None yet; this specification precedes its first implementation deliberately. The construction it adapts is fielded at scale in WhatsApp, Signal groups, and Matrix (Megolm). A cryptographic review of this document by a qualified adversarial reviewer is a prerequisite to any implementation carrying real conversations. + +## References + +- Megolm group ratchet (design template; Apache-2.0): https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md +- Signal Double Ratchet, revision 4: https://signal.org/docs/specifications/doubleratchet/ +- Signal X3DH: https://signal.org/docs/specifications/x3dh/ +- MLS, RFC 9420: https://datatracker.ietf.org/doc/html/rfc9420 +- Marmot Protocol (MLS over Nostr): https://github.com/marmot-protocol/marmot +- Balbás, Collins, Gajland — "WhatsUpp with Sender Keys? Analysis, Improvements and Security Proofs" (ASIACRYPT 2023): https://eprint.iacr.org/2023/1385 ; companion analysis: https://arxiv.org/abs/2301.07045 +- Nostr NIP-44 (secp256k1 payload reference and ECDH caveats): https://github.com/nostr-protocol/nips/blob/master/44.md +- HKDF, RFC 5869: https://www.rfc-editor.org/rfc/rfc5869 +- DHKEM-secp256k1 CFRG draft: https://datatracker.ietf.org/doc/draft-wahby-cfrg-hpke-kem-secp256k1/ +- [BRC-42: BSV Key Derivation Scheme](../key-derivation/0042.md) · [BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties](../key-derivation/0043.md) +- [BRC-78: Serialization Format for Portable Encrypted Messages](./0078.md) +- [BRC-33: PeerServ Message Relay Interface](./0033.md) · [BRC-169: Universal Handle Addressing and Resolution for the Metanet](./0169.md) +- [BRC-146: Access Gates for Metanet Rooms](../apps/0146.md) · [BRC-311: BAP — Bitcoin Attestation Protocol](./0311.md) · [BRC-312: Bitcoin Schema — Social Data Types](../apps/0312.md) diff --git a/peer-to-peer/README.md b/peer-to-peer/README.md index 081a251..e725673 100644 --- a/peer-to-peer/README.md +++ b/peer-to-peer/README.md @@ -20,3 +20,5 @@ BRC | Standard 141 | [Fountain-Coded Air-Gap Transport for Arbitrary Payloads](./0141.md) 169 | [Universal Handle Addressing and Resolution for the Metanet](./0169.md) 225 | [Animated-QR Air-Gap Transport for Arbitrary Payloads (TKQR1)](./0225.md) +311 | [BAP — Bitcoin Attestation Protocol](./0311.md) +313 | [Encrypted Group Messaging over Type-42 Key Derivation](./0313.md) diff --git a/scripts/0300.md b/scripts/0300.md new file mode 100644 index 0000000..9844ebd --- /dev/null +++ b/scripts/0300.md @@ -0,0 +1,257 @@ +# BRC-300: Bitcom — Universal Bitcoin Computer: Decentralized Protocol Registry and Composition + +Open Protocol Labs (info@opl.dev) + +**Authors:** _unwriter (original author), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Gal Buki (torusJKL) — "$" admin mode ("Bitcom as OS"); Rangel Wulff — extensible protocol / pipeline inspiration; Steve Shadders — transformation and markup protocol ideas; Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +Bitcom is a set of conventions, introduced by _unwriter in early 2019, for creating, identifying, administering, and composing application-layer OP_RETURN protocols on Bitcoin SV without any central registry. A protocol is identified by an ordinary Bitcoin P2PKH address generated by its creator; the address serves as a globally unique, collision-resistant namespace prefix, and control of the corresponding private key constitutes ownership of the protocol. Bitcom additionally defines an admin command convention (a `$` push datum, authenticated by spending from the account's own address) for registering accounts and publishing protocol metadata on-chain, a pipeline convention (push data `|`) for composing multiple protocols within a single OP_RETURN output, and an on-chain schema publication scheme so that protocol semantics are machine-readable. + +These conventions underpin many widely deployed OP_RETURN protocols, including B, MAP, AIP, and BAP, and remain in active use. This document articulates the Bitcom conventions as a standard so that they can be referenced normatively by other BRCs. + +## Motivation + +Before Bitcom, OP_RETURN protocols identified themselves with short arbitrary "magic" prefixes (for example, Memo's `0x6d01`-style two-byte codes). Arbitrary prefixes have two problems: + +1. **Collision.** Nothing prevents two protocols from choosing the same prefix, and short prefixes make accidental collision likely as the number of protocols grows. +2. **Central registration.** Avoiding collisions otherwise requires a curated registry — a central point of failure and human politics, at odds with a permissionless network that must support an unbounded number of protocols. + +Central registries were in fact attempted — for example the Bitcoin Cash protocol repository, a CSV file on GitHub to which developers submitted 4-byte prefixes. The original documentation identifies four problems with that model: a high barrier to creating protocols, a manual process that cannot be automated (protocols could not programmatically create protocols), centralization and its politics, and no fundamental fix (nothing stops collisions with unlisted or defiant prefixes). + +Bitcom solves both problems by deriving the namespace from Bitcoin itself: generating a fresh keypair yields an address whose uniqueness is guaranteed by the same cryptographic assumptions that secure coin ownership, and whose private key doubles as an ownership credential for administering the protocol. Registration is self-service — announcing the address on-chain from the address itself — and administration happens purely through ordinary transactions. As the original documentation puts it: "Nobody owns Bitcom. It's just an open convention you can use to build your application protocols." + +The approach became economical with Bitcoin SV's Block 566476, which lifted the de-facto ~220-byte OP_RETURN limit: once payloads are measured in kilobytes, a 25-byte address prefix costs no more in practice than a 4-byte magic value, while buying collision-free, permissionless, ownable namespaces. + +The composition and schema conventions extend the same philosophy — drawn explicitly from the Unix design tradition — to protocol interoperability: each protocol stays minimal and single-purpose, protocols are composed through a pipeline rather than by growing monolithic specifications, and each protocol's push-data semantics can be published on-chain in machine-readable form. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Protocol Identifier + +A Bitcom protocol is identified by a Bitcoin P2PKH address, encoded in Base58Check, generated by the protocol's creator. + +- The creator generates an ordinary keypair. The resulting address is the protocol's identifier and namespace prefix. No third party is involved; the account is announced on-chain with `$ useradd` (Section 3.2). +- Uniqueness follows from the collision resistance of address generation; no central allocation is needed. +- The holder of the corresponding private key is the protocol's **admin**. Administrative actions (Section 3) are authenticated by demonstrating control of this key. +- In the Unix filesystem metaphor, each account is a root folder named by its address, and the account's metadata files (Section 3.3) live inside it. + +For example, the B protocol is identified by the address `19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`. + +#### 1.1 String Identifiers in Practice (Informative) + +Several deployed protocols adopt Bitcom's data format (Section 2) and pipeline composition (Section 4) while using a plain human-readable UTF-8 string as the protocol identifier instead of an address. The original RUN token protocol used the string `run`; the Sigma signing protocol uses the string `SIGMA`. Consumers identify these protocols by exact string match. + +Such protocols deliberately forfeit what the address-as-prefix rule provides: there is no collision resistance beyond the string's distinctiveness, and — with no underlying keypair — no provable ownership, no authenticated `$` administration, and no route enablement. They nonetheless compose cleanly in pipelines alongside address-identified protocols, and indexers built on the positional push-data model handle both identically. + +### 2. Protocol Data Format + +A transaction output invoking a Bitcom-style protocol is a data-carrier output in which the first push datum after `OP_RETURN` is the protocol's address, encoded as a UTF-8 string: + +``` +OP_RETURN + + + + ... +``` + +All push data following the protocol address are defined by that protocol's own specification. Bitcom itself imposes no structure on them beyond the conventions in Sections 3–5. + +**Note on OP_FALSE OP_RETURN:** Bitcom predates the Genesis upgrade. Original Bitcom-era transactions used a bare `OP_RETURN`. Post-Genesis transactions use the `OP_FALSE OP_RETURN` false-return template ([BRC-18](./0018.md)); the Bitcom conventions apply identically, with the protocol address as the first push datum after `OP_RETURN`. Indexers supporting historical data SHOULD recognize both forms. + +### 3. Admin Commands + +Bitcom defines administrative commands for registering an account and publishing metadata into its namespace. An admin transaction is a data-carrier output whose **first push datum is `$`** (a single UTF-8 dollar sign), followed by a command and its arguments: + +``` +OP_RETURN + $ + + +``` + +#### 3.1 Identification and Authentication + +The account an admin command acts upon is identified by the transaction's **funding input**: admin transactions are sent from the protocol address itself, and verifiers and indexers attribute a `$` command to the address of the spending input (in BitDB query terms, `in.e.a`). Because only the private key holder can spend from the address, this simultaneously authenticates the action. Transactions matching the `$` syntax whose inputs do not spend from the claimed account MUST NOT be treated as administrative actions of that account — as the original documentation notes, anyone can push a random address into an OP_RETURN, but "we can just check the sender info to see that the sending address matches." + +#### 3.2 `useradd` — Register an Account + +Generating a keypair creates a potential namespace, but the account exists on the network only once it is announced on-chain: + +``` +OP_RETURN $ useradd
+``` + +where `
` is the account's own address (the transaction is funded from that same address, per Section 3.1). Once confirmed, the sender provably owns that address space. + +#### 3.3 `echo` — Write a Metadata File + +Writes content to a named virtual file in the account's root (note the Unix `>` redirection is spelled `to`): + +``` +OP_RETURN $ echo to +``` + +Conventional filenames include `description` (a human-readable protocol description) and `schema.json` (Section 5). Later writes to the same filename supersede earlier ones. + +#### 3.4 `cat` — Assign On-Chain Content to a File + +Assigns previously published on-chain content, referenced by a `bit://` URI (Section 6), to a filename in the account's root: + +``` +OP_RETURN $ cat bit:/// to +``` + +This allows large documents (for example a README stored via the B protocol) to be attached to a protocol by reference rather than inline. The import is logical, not physical; retrieval is performed by indexers. + +#### 3.5 `route` — Decentralized Endpoint Routing + +The `route` commands connect on-chain protocol identifiers to off-chain service endpoints, enabling `bit://` URI resolution (Section 6). + +**`route enable`** — performed by the protocol admin only. Opens a route pattern for service providers to implement: + +``` +OP_RETURN $ route enable +``` + +**`route add`** — performed by any service provider. Advertises an endpoint implementing an enabled route: + +``` +OP_RETURN $ route add +``` + +Example: + +``` +OP_RETURN $ route add 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut /:tx https://media.bitcoinfiles.org/{{tx}} +``` + +Providers SHOULD use a separate service account for `route add` rather than the protocol admin account; the admin account should only enable routes. + +Route matchers follow the pattern language of route-parser: `:name` captures a parameter up to `/`, `?`, or end of string; `*name` captures a splat up to `?` or end of string; `(...)` denotes an optional group (which may nest); anything else is a literal. The endpoint template instantiates captured variables into a static URI. Both `{{tx}}`-style and `${tx}`-style template variables appear in the original documentation (the website and the 0.1.0 release notes respectively); resolvers processing historical transactions should be aware both spellings exist on-chain. + +A provider's claimed affiliation with a protocol is not proven by `route add` alone; consumers MAY require additional verification schemes (such as the Bitcoin Sticker Protocol) before trusting an advertised endpoint. + +#### 3.6 Embedded Admin Mode ("Bitcom as OS") + +A later design iteration, proposed by torusJKL and adopted in the Bitcoin Script Schema proposal, embeds the admin layer *inside* a protocol's own prefix namespace rather than treating Bitcom as a standalone protocol — "an OS that gets installed into protocols." In this form the protocol address precedes the `$`: + +``` +OP_RETURN + + $ + + +``` + +Authentication is unchanged: the transaction is funded from the protocol address (Section 3.1), with the output additionally carrying the address as its first push datum. Schema publication (Section 5) is specified in this embedded form. Indexers supporting Bitcom SHOULD recognize both the plain form (`$` first, Sections 3.2–3.5) and the embedded form (address first). + +#### 3.7 Client-Side Commands + +The original Bitcom CLI and its successor shell bitsh also implemented purely local commands (`init` for keypair generation into a `.bit` file, `whoami`, `ls`, `history`). These manage client-side state and produce no on-chain footprint; they are informative only. + +### 4. Pipeline Composition + +Multiple protocols MAY be composed within a single OP_RETURN output using the push datum `|` (a single UTF-8 pipe character) as a separator: + +``` +OP_RETURN + + | + + | + +``` + +Semantics, following the Unix pipeline: + +1. Each segment begins with a protocol address and is interpreted by that protocol's specification. +2. Order is significant and linear: conceptually, each protocol's output object is passed as input to the next protocol in the pipe. A fixed order (unlike an unordered `&` composition) means each composite template has exactly one canonical form, keeping it queryable with a single pattern. +3. The pipeline is atomic: all segments are part of one output in one transaction, so a data payload and its metadata, signatures, or rights assignments are bound together irrevocably. +4. Producer-only protocols (those that originate data rather than transform it, such as B) appear at the head of a pipeline. + +Example — store a file, attach video metadata, and assign admin rights, using three separate protocols in one atomic output: + +``` +OP_RETURN + 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut [DATA] video/mp4 | + 1EKrfyTD6UoXR85vpfxZ7e8h2h8C5XEroy video.mp4 60 | + 1M16gTfEL8f6SkXnTzBepF56KDNG9Qka7Y SET ADMIN +``` + +This convention lets each protocol remain minimal — new capabilities are added by piping into additional protocols rather than by extending a base protocol and accumulating technical debt. The pipeline convention does not strictly require the address-prefix convention, but the two are designed to be used together. + +### 5. Schema Publication (Bitcoin Script Schema) + +A protocol SHOULD publish a machine-readable schema describing the meaning of its push data, so that indexers and applications can interpret protocol transactions without relying on prose documentation. The schema scheme is based on the BitDB transaction serialization format, in which output push data are addressed positionally (`out.s1` is the first push datum as a UTF-8 string, `out.s2` the second, and so on; `out.h2` is the second push datum as hex). + +A schema is a JSON document: + +```json +{ + "v": 1, + "s": { + "out.s2": "{{blob}}", + "out.s3": "{{mediatype}}" + } +} +``` + +- `v` — schema scheme version number. +- `s` — schema description: a mapping from positional push-data selectors to attribute names. Values wrapped in `{{ }}` are attribute variables; unwrapped values are static literals used for pattern matching. A protocol with multiple message patterns expresses `s` as an array of such mappings, with static literals (for example `"out.h2": "01"`) selecting which pattern applies. + +The schema is published on-chain in the protocol's own namespace using the `$ echo` command in embedded admin form (Section 3.6): + +``` +OP_RETURN + 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut + $ + echo + {"v":1,"s":{"out.s2":"{{blob}}","out.s3":"{{mediatype}}"}} + to + schema.json +``` + +Publishing a schema constitutes the protocol's public, immutable, machine-readable interface definition: consumers locate it by querying for the protocol address with the `$` / `echo` / `to` / `schema.json` pattern (authenticated per Section 3.1) and then parse protocol transactions accordingly. + +### 6. The `bit://` URI Scheme + +Objects published under Bitcom protocols are referenced with the generic URI form: + +``` +bit:/// +``` + +For example, a file stored with the B protocol is referenced as `bit://19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut/`. Resolution is decentralized: any service provider that has advertised an endpoint for a matching enabled route (Section 3.4) can serve the referenced object, and clients choose among advertised providers. + +The original documentation states that where a protocol has its own shorthand URI scheme, the `bit://` form points to the same content — "the `bit://19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut` prefix part is equivalent to `b://`" — and recommends the `bit://` scheme going forward. This equivalence is of referent, not of resolution mechanism: a protocol's own scheme may be served by dedicated gateways independent of the route advertisements in Section 3.4. + +### 7. Security and Ownership Considerations + +- The protocol private key is the sole root of administrative authority. Loss of the key means permanent loss of the ability to publish or update protocol metadata; compromise of the key means an attacker can publish authentic-looking metadata. Protocol creators SHOULD protect the protocol key accordingly and SHOULD NOT reuse it for other purposes. +- None of these conventions are consensus-enforced. They are interoperability conventions: anything can be written on-chain, and it is verifiers and indexers that give authenticated admin actions their meaning by applying the checks in Section 3.1. +- Route advertisements are open by design; endpoint trust is a client-side decision (Section 3.4). + +## Implementations + +- **Bitcom CLI** — the original `bitcom` npm package (`bit` command), building and broadcasting the transactions described here: https://github.com/unwriter/Bitcom +- **bitsh** — interactive shell ("Bash for Bitcom") with HD wallet support under `~/.bitcom`: https://github.com/interplanaria/bitsh +- **bit** — the `bit://` URI scheme and routing implementation: https://github.com/interplanaria/bit +- **B protocol** — the canonical example protocol whose prefix was generated under this convention: https://github.com/unwriter/B +- Protocols in active production use that follow the Bitcom address-prefix and pipeline conventions include B (`19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`), MAP (`1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5`), AIP (`15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva`), and BAP (`1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT`), with parsers and indexers such as bpu, bob, bmap, and bmap-api built on the positional push-data model of Section 5. + +## References + +- Bitcom repository (README and 0.1.0 release notes): https://github.com/unwriter/Bitcom +- "Bitcom as OS" (admin mode design, proposed by torusJKL): https://github.com/unwriter/Bitcom/issues/1 +- "Bitcom Unix Pipeline" (pipeline design and inspirations): https://github.com/unwriter/Bitcom/issues/2 +- "Bitcoin Script Schema" (on-chain schema publication): https://github.com/unwriter/Bitcom/issues/3 +- Original Bitcom website documentation (archived): https://web.archive.org/web/20211209081820/https://bitcom.bitdb.network/#/ +- route-parser pattern language: https://github.com/rcs/route-parser +- [BRC-18: Pay to False Return](./0018.md) +- [BRC-13: TXO — Transaction Object Format](../transactions/0013.md) (positional push-data serialization used by the schema scheme) diff --git a/scripts/0301.md b/scripts/0301.md new file mode 100644 index 0000000..bde166e --- /dev/null +++ b/scripts/0301.md @@ -0,0 +1,121 @@ +# BRC-301: B — Bitcoin Data Protocol + +Open Protocol Labs (info@opl.dev) + +**Authors:** _unwriter (original author), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +B is an OP_RETURN protocol to **store** and **reference** arbitrary data on Bitcoin. A B transaction carries raw file content together with its media type, character encoding, and optional filename under the protocol prefix `19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut` (a [BRC-300](./0300.md) address identifier, generated using Bitcom). Stored media is addressed by the transaction id that carries it and referenced from other on-chain media with the `b://` URI scheme, making B the foundational content layer for on-chain websites, images, and documents composed with companion attribute and identity protocols such as MAP and AIP. + +## Motivation + +B's design goals: + +1. The simplest protocol to upload arbitrary media to the blockchain. +2. A protocol to **reference** previously uploaded media from another **on-chain media**. + +Before B, on-chain content schemes packed data and metadata into ad-hoc formats. B stores content as raw push data with just enough metadata (IANA media type and encoding) for any application to interpret it, and its reference scheme lets on-chain documents link to one another — an HTML page embedding an on-chain image, markdown linking to an on-chain page — so that entire websites can live on Bitcoin. + +B became economical with the lifting of the OP_RETURN size limit at Bitcoin SV Block 566476 (see [BRC-300](./0300.md), Motivation), which made kilobyte- and megabyte-scale payloads practical. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Protocol Format + +A B transaction is a data-carrier output ([BRC-18](./0018.md)) whose push data are: + +``` +OP_RETURN + 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut + [Data] + [Media Type] + [Encoding] + [Filename] +``` + +| Order | Field | Meaning | +|-------|-------|---------| +| 1 | Data | The raw content to store, written **directly as binary push data** (not Base64 or hex text). | +| 2 | Media Type | A media type as listed in the IANA Media Types registry (e.g. `image/png`, `text/html`, `text/markdown`). | +| 3 | Encoding | A character set as listed in the IANA Character Sets registry. Default: `binary`. MAY be omitted for binary blobs. | +| 4 | Filename | A filename to store the blob as. Default: none — the blob is identified simply by its txid. MAY be omitted. | + +The field order is deliberate — `data`, `media type`, `encoding`, `filename`, in order of significance — leaving room for future extensibility through additional push data. + +Examples: + +``` +OP_RETURN 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut hello world text/html UTF-8 hello.html + +OP_RETURN 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut [file bytes] image/png binary duck.png + +OP_RETURN 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut [file bytes] image/png +``` + +### 2. Referencing Media (`b://`) + +Stored media is addressed by the transaction id of the transaction that carries it and referenced with the URI form: + +``` +b:// +``` + +References work from ANY other on-chain media. An on-chain HTML page can embed an on-chain image: + +```html + +``` + +link to another on-chain page: + +```html +my website! +``` + +or appear in on-chain markdown: + +```markdown +![image](b://46e1ca555622e73708a065f92df0af2cc0fe00ed1dd352d5fb8510365050347c) +``` + +B's specification defines only the `b://` form. How a client resolves a `b://` URI to a serving endpoint is outside this specification. + +**Informative note:** the Bitcom documentation ([BRC-300](./0300.md) §6) states that `bit://19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut/` is equivalent to `b://` — both point to the same content — and recommended the `bit://` form for new references. That equivalence is a claim of the Bitcom documentation, not of B itself. + +### 3. Composition + +B is a **producer-only** protocol in [BRC-300](./0300.md) pipeline terms: it originates data rather than transforming piped input, so a B segment appears at the head of a pipeline. Attributes, authorship, and other concerns are layered by piping into companion protocols: + +``` +B | MAP SET type post | AIP BITCOIN_ECDSA
+``` + +This composition — content in B, attributes in MAP, authorship in AIP — keeps B itself minimal while supporting arbitrarily rich applications. (MAP and AIP are specified in their own BRCs.) + +### 4. Non-Goals + +B is NOT a protocol for handling authenticated or encrypted media. Its design goals are: + +1. **Public:** public assets. +2. **Simple:** simple to implement. +3. **Versatile:** easily pluggable into any application in any context. +4. **Extensible:** future extensibility with additional push data support. + +Authentication is layered on with companion signature protocols such as AIP or Sigma (specified in their own BRCs); encryption is out of scope entirely. + +## Implementations + +B has been one of the most heavily used data protocols on Bitcoin SV since 2019, with content-serving gateways, parsers, and indexers in production across the ecosystem. The canonical specification is maintained at https://github.com/unwriter/B. + +## References + +- B repository (canonical specification): https://github.com/unwriter/B +- [BRC-300: Bitcom](./0300.md) — protocol prefix, pipeline, and `bit://` routing conventions +- [BRC-18: Pay to False Return](./0018.md) — data-carrier output template +- IANA Media Types: https://www.iana.org/assignments/media-types/media-types.xhtml +- IANA Character Sets: https://www.iana.org/assignments/character-sets/character-sets.xhtml diff --git a/scripts/0302.md b/scripts/0302.md new file mode 100644 index 0000000..79925db --- /dev/null +++ b/scripts/0302.md @@ -0,0 +1,155 @@ +# BRC-302: AIP — Author Identity Protocol + +Open Protocol Labs (info@opl.dev) + +**Authors:** Attila Aros, Luke Rohenaz (luke@opl.dev) + +**Contributors:** Monkeylord, _unwriter, Libitx — feedback and ideas on the original specification; Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +The Author Identity Protocol (AIP) is a simple and flexible method for signing arbitrary OP_RETURN data with Bitcoin ECDSA signatures. An AIP instance is appended to a data-carrier output as a [BRC-300](./0300.md) pipeline segment under the prefix `15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva`, carrying a signing algorithm, a signing address, a signature, and an optional list of field indexes selecting exactly which push data the signature covers. Because the signing key is independent of the transaction's funding keys, authorship can be proven without exposing the author's identity through an on-chain payment, and multiple signatures can be layered in one output to form multi-party agreements. + +## Motivation + +AIP's design goals: + +- A simple protocol to sign arbitrary OP_RETURN data in a single transaction. +- Decouple signing identity from the funding source address — no on-chain transaction from the signing identity address is required. +- Allow multiple signatures to be layered to form multi-party contracts. + +Decoupling identity from funding means an author can, for example, publish a document while a wallet or faucet pays the mining fee, without the author's identity key ever appearing in an on-chain payment. Content protocols such as B ([BRC-301](./0301.md)) and attribute protocols such as MAP deliberately carry no identity scheme of their own; AIP is the companion protocol that binds authorship to their data. + +The technique was inspired by Monkeylord's bitcoin-ibe work and builds on _unwriter's B data protocol. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Placement and Format + +An AIP instance occupies a [BRC-300](./0300.md) pipeline segment in a data-carrier output ([BRC-18](./0018.md)), following the fields it signs: + +``` +OP_RETURN + <...data fields being signed...> + | + 15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva + + + + [ ...] +``` + +The fields being signed MUST appear before (to the left of) the AIP prefix. Any OP_RETURN content can be signed — the example above shows AIP appended after arbitrary data fields, separated by the Bitcom pipe `|`. + +### 2. Fields + +| Order | Field | Encoding | Meaning | +|-------|-------|----------|---------| +| 1 | Signing Algorithm | UTF-8 push | Signature scheme identifier. `BITCOIN_ECDSA` denotes the Bitcoin Signed Message scheme defined in Section 3. | +| 2 | Signing Address | UTF-8 push | Base58Check P2PKH address corresponding to the signing key. | +| 3 | Signature | binary push (65 bytes) | Compact recoverable ECDSA signature: 1 recovery byte followed by 32-byte `r` and 32-byte `s`. Commonly displayed in Base64 off-chain. | +| 4+ | Field Index (optional, repeating) | minimally-encoded unsigned integer push | Indexes of the fields covered by the signature (Section 4). If omitted entirely, all fields to the left of the AIP prefix are signed. | + +`BITCOIN_ECDSA` is the algorithm defined by this specification. Some implementations accept `BitcoinSignedMessage` as a synonym for the same scheme, and a `paymail` variant exists in which the signing component is a compressed public key (hex) rather than an address; verifiers that do not implement an algorithm MUST treat those instances as unverified rather than valid. + +### 3. Signed Message Construction + +The message covered by the signature is the **concatenation of the raw bytes of the selected fields, in index order**: + +``` +message = field[i₀] || field[i₁] || ... || field[iₙ] +``` + +where each `field[k]` is the raw byte content of the push datum at index `k` per Section 4 (for index 0, the single byte `0x6a`). + +Signing and verification then follow the Bitcoin Signed Message (BSM) scheme: the message is prefixed with the string `"Bitcoin Signed Message:\n"` (each component varint-length-prefixed), hashed with double SHA-256, and signed with a compact recoverable ECDSA signature over secp256k1. A verifier recovers the public key from the signature and message, derives its P2PKH address, and the instance is **valid** if and only if the derived address equals the Signing Address field. + +### 4. Field Indexing + +Field indexes are zero-based positions within the output script: + +- **Index 0 is the `OP_RETURN` opcode itself** — the single byte `0x6a`. (In post-Genesis `OP_FALSE OP_RETURN` outputs, the leading `OP_FALSE` is not indexed.) +- Index `k` (k ≥ 1) is the k-th push datum following `OP_RETURN`; its content is the raw pushed bytes, excluding the push opcode and length prefix. +- The Bitcom pipe `|` is an ordinary push datum (`0x7c`) and occupies an index like any other field. + +**Explicit indexing:** the AIP instance lists each covered index as a trailing field. Indexes select any subset of fields, enabling a signature to cover some fields while excluding others. + +**Implicit signing (index list omitted):** the signature covers **all** fields from index 0 up to and including the `|` separator immediately preceding the AIP prefix. + +A null field is represented by the push datum `0x00` and contributes the single byte `0x00` to the message. + +### 5. Multiple Signatures + +Additional AIP instances MAY be appended as further pipeline segments, each covering the fields selected by its own index list. Because each signature can cover the same content fields (and, with explicit indexes, exclude the other signatures), multiple parties can sign one document in a single output, forming an on-chain multi-party agreement. + +### 6. Verification Procedure + +To verify an AIP instance: + +1. Parse the output script into indexed fields per Section 4 and locate the AIP prefix segment. +2. Read the Signing Algorithm, Signing Address, and Signature fields, and the trailing index list if present. +3. Determine the covered field set: the explicit index list, or the implicit range per Section 4. +4. Concatenate the raw bytes of the covered fields in index order (Section 3). +5. Verify the compact signature over the concatenation under the BSM scheme against the Signing Address. + +An instance whose algorithm is unrecognized, whose signature does not verify, or whose index list references fields that do not exist is **invalid**. + +## Example + +A B file signed with a single AIP signature listing its covered indexes explicitly: + +``` +OP_RETURN + 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut // B prefix + { "message": "Hello world!" } // Content + application/json // Media Type + UTF-8 // Encoding + 0x00 // Filename (null) + | // Pipe separating protocols + 15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva // AIP prefix + BITCOIN_ECDSA // Signing Algorithm + 1EXhSbGFiEAZCE5eeBvUxT6cBVHhrpPWXz // Signing Address + <65-byte signature> // Signature + 0, 1, 2, 3, 4, 5, 6 // Field indexes: OP_RETURN, the five B fields, and the pipe +``` + +The same transaction in raw push-data (hex) form: + +``` +6a OP_RETURN (index 0) +31394878696756345179427633744870515663554551797131707a5a56646f417574 B prefix (index 1) +7b20226d657373616765223a202248656c6c6f20776f726c6421227d content (index 2) +6170706c69636174696f6e2f6a736f6e application/json (index 3) +7574662d38 utf-8 (index 4) +00 null filename (index 5) +7c | (index 6) +313550636948473232534e4c514a584d6f5355615756693757537163376843667661 AIP prefix +424954434f494e5f4543445341 BITCOIN_ECDSA +31455868536247466945415a4345356565427655785436634256486872705057587a signing address +1b3ffcb62a3bce00c9b4d2d66196d123803e31fa88d0a276c125f3d2524858f4d16b +f05479fb1f988b852fe407f39e680a1d6d954afa0051cc34b9d444ee6cb0af signature +00 01 02 03 04 05 06 field indexes +``` + +Omitting the seven index pushes yields the implicit form, with identical coverage. + +On-chain transaction examples: + +- One signature: [`db61b9a0…deac753`](https://whatsonchain.com/tx/db61b9a0a31142825a9f2f1c48543299f72c974b5e4c44335c4357abfdeac753) +- Two signatures: [`d4738845…f0de311`](https://whatsonchain.com/tx/d4738845dc0d045a35c72fcacaa2d4dee19a3be1cbfcb0d333ce2aec6f0de311) +- Implicit sign-all: [`5633bb96…867092c`](https://whatsonchain.com/tx/5633bb966d9531d22df7ae98a70966eebe4379d400d74ac948bf5b4f2867092c) + +## Implementations + +AIP signatures have been produced and verified in production since 2019; open-source signing and verification libraries exist in multiple languages. The canonical specification is maintained at https://github.com/opldotdev/AIP. + +## References + +- AIP repository (canonical specification): https://github.com/opldotdev/AIP +- [BRC-300: Bitcom](./0300.md) — protocol prefix and pipeline conventions +- [BRC-301: B — Bitcoin Data Protocol](./0301.md) — content commonly signed with AIP +- [BRC-18: Pay to False Return](./0018.md) — data-carrier output template +- bitcoin-ibe (Monkeylord): https://github.com/monkeylord/bitcoin-ibe +- B protocol (_unwriter): https://github.com/unwriter/B diff --git a/scripts/0303.md b/scripts/0303.md new file mode 100644 index 0000000..113f2a8 --- /dev/null +++ b/scripts/0303.md @@ -0,0 +1,223 @@ +# BRC-303: MAP — Magic Attribute Protocol + +Open Protocol Labs (info@opl.dev) + +**Authors:** Luke Rohenaz (luke@opl.dev), Attila Aros + +**Contributors:** _unwriter — input and support on the original specification; Kurt Wuckert Jr. (kurt@opl.dev), David Case (dcase@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +The Magic Attribute Protocol (MAP) is a key/value datastore protocol for Bitcoin. It defines a small command set for associating arbitrary attributes with data in a transaction output — setting and removing single key/value pairs, adding and deleting members of lists, and targeting previously written records by transaction id — all expressed as OP_RETURN push data under the protocol prefix `1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5` ([BRC-300](./0300.md) address-as-prefix convention). MAP deliberately provides data mapping without enforcing any content, authority, or identity scheme; those concerns are delegated to companion protocols composed in the same output via the [BRC-300](./0300.md) pipeline, such as B ([BRC-301](./0301.md)) for content and AIP ([BRC-302](./0302.md)) for authorship signatures. + +## Motivation + +MAP's design goals: + +- A simple OP_RETURN protocol for associating data in a single transaction by defining key/value pairs. +- A flexible protocol suitable for many applications. +- Compatibility with faucets and other situations where the funding input address does not represent the author's public identity. +- Data mapping without enforcing a content, authority, or identity scheme — other protocols provide these. + +Typical uses: map a comment to a URL, map an action (like, repost, flag) to a transaction hash, map a photo to a geolocation, map a `type` to content (a post, a reply), or attach metadata to a Metanet node. + +The command set is modeled on familiar programming interfaces. JavaScript's `localStorage` offers `setItem(key, value)` and `removeItem(key)`; a JavaScript `Set` offers `add` and `delete`. In web programming the browser session and domain establish context implicitly — but Bitcoin is one giant shared context, so MAP provides `SELECT` to designate a context explicitly by transaction id: + +| JavaScript | MAP | +| ------------------------------------- | ----------------- | +| `localStorage.setItem(key, value)` | `SET key value` | +| `localStorage.removeItem(key)` | `SELECT` + `REMOVE key` | +| `set.add(value)` | `ADD key value` | +| `set.delete(value)` | `SELECT` + `DELETE key value` | +| `localStorage.clear()` / `set.clear()`| `CLEAR txid` | + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Protocol Format + +MAP data is carried in a data-carrier output ([BRC-18](./0018.md)) whose push data begin with the MAP protocol prefix, followed by a command and its arguments: + +``` +OP_FALSE OP_RETURN + 1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 + + +``` + +All push data are UTF-8 strings unless an application specifies otherwise. The prefix is a [BRC-300](./0300.md) protocol identifier; MAP composes with other protocols in a single output via the `|` pipeline separator (Section 6). + +### 2. Commands + +MAP defines six commands. `SET`, `SELECT` + `REMOVE` operate on single-value keys; `ADD`, `SELECT` + `DELETE` operate on list-valued keys; `CLEAR` erases whole records. + +#### 2.1 `SET` — Associate Keys with Values + +Associates one or more keys with one value each. Key/value arguments repeat in pairs, allowing multiple attributes to be set at once: + +``` +SET + + +[ ...] +``` + +Example — three attributes in one command: + +``` +1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 +SET +app +metalens +type +comment +url +https://twitter.com +``` + +#### 2.2 `ADD` — Append Values to a List + +Appends one or more values to a list-valued key: + +``` +ADD + + +[ ...] +``` + +#### 2.3 `SELECT` — Designate a Context + +Designates a previously written transaction as the context for the commands that follow it: + +``` +SELECT + + + +``` + +- `SELECT` MUST be followed by one of `SET`, `REMOVE`, `ADD`, or `DELETE`. +- `SELECT` SHOULD appear only once per instruction set (Section 3), since it establishes the context for the subsequent commands of that set. +- Omitting `SELECT` means the current transaction itself is the context. +- If the selected transaction is a Metanet node, the command applies to that node and its children. + +#### 2.4 `REMOVE` — Remove a Key + +Used with `SELECT`. Removes a previously `SET` key, or all values of a list-valued key at once: + +``` +SELECT + +REMOVE + +[ ...] +``` + +#### 2.5 `DELETE` — Remove Values from a List + +Used with `SELECT`. Removes one or more specific values from a list-valued key: + +``` +SELECT + +DELETE + + +[ ...] +``` + +#### 2.6 `CLEAR` — Erase Records + +Erases every MAP value previously written by a given transaction, whether single-value or list-valued. The txid argument MAY repeat to clear multiple transactions at once: + +``` +CLEAR + +[ ...] +``` + +**Note on Metanet usage:** when MAP is used together with the Metanet protocol, the preferred way to update data is to write a new version of the Metanet node replacing the outdated one, which eliminates the need for `REMOVE` or `DELETE` in many cases. + +### 3. Command Separator (`:::`) + +Multiple MAP commands MAY be declared in a single output using the separator push datum `:::`. Commands joined this way form one **instruction set** and share context, without repeating the protocol prefix: + +``` +1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 +SET +key +val +::: +ADD +key2 +val +val +val +``` + +This evaluates as `MAP SET key val` followed by `MAP ADD key2 val val val`, in a single output. + +### 4. Multiple Outputs + +A transaction MAY carry MAP instruction sets in multiple data-carrier outputs. Independent instruction sets targeting different contexts SHOULD be placed in separate outputs rather than joined by pipes with no data flow between them: + +``` +output 1: MAP SELECT DELETE key val1 val2 ::: REMOVE key4 +output 2: MAP SELECT DELETE key val1 val2 ::: REMOVE key4 +``` + +### 5. Keys + +The keyspace is shared and open. Applications MAY either prefix keys with a unique identifier or operate in the global space, sharing the dataset and inheriting the emergent schema — useful when data is intended to be shared among many apps. Established global-identifier namespaces include `url`, `tx`, `topic`, `upc`, `isbn`, and hash names such as `md5`. + +Compound attributes use dot notation by convention: + +``` +coordinates.lat / coordinates.lng / coordinates.alt +profile.name / profile.text / profile.image +``` + +Keys can name nouns (namespaces) or verbs (actions). Action keys typically act on something that already exists and need no content input — for example `MAP SET like true tx ` — beginning a new chain rather than taking piped input from a previous protocol. + +### 6. Composition + +MAP is designed to be chained with other OP_RETURN protocols using the [BRC-300](./0300.md) pipeline. The input stream flows from the left, like Unix pipes. A common pattern attaches content with B, maps attributes with MAP, and signs authorship with AIP ([BRC-302](./0302.md)): + +``` +OP_FALSE +OP_RETURN +19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut (B) +## Hello small world +text/markdown +utf8 +| +1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 (MAP) +SET +type +comment +url +https://twitter.com +| +15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva (AIP) +BITCOIN_ECDSA +
+ +``` + +Because MAP does not itself carry an identity scheme, signing with AIP is the standard way to bind authorship: the AIP signature covers the fields to its left, including the MAP data. + +## Implementations + +MAP has been in continuous production use since 2019 across BSV social and metadata applications; open-source parsers and indexers for the protocol exist in multiple languages. The canonical specification is maintained at https://github.com/opldotdev/MAP. + +## References + +- MAP repository (canonical specification): https://github.com/opldotdev/MAP +- [BRC-300: Bitcom](./0300.md) — protocol prefix and pipeline conventions +- [BRC-302: AIP — Author Identity Protocol](./0302.md) — authorship signatures over MAP data +- [BRC-18: Pay to False Return](./0018.md) — data-carrier output template +- [BRC-301: B — Bitcoin Data Protocol](./0301.md) +- Metanet protocol: https://nchain.com/en/the-metanet/ +- Memo protocol (Jason Chavannes) — prior work compared against in the original MAP specification: https://memo.sv/protocol diff --git a/scripts/0304.md b/scripts/0304.md new file mode 100644 index 0000000..3c9efd0 --- /dev/null +++ b/scripts/0304.md @@ -0,0 +1,198 @@ +# BRC-304: Sigma — Transaction-Bound Script Signatures + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +Sigma is a digital signature scheme for signing Bitcoin transaction output scripts. A Sigma instance attaches a signature to an output script such that the signature is bound to (1) a chosen **input outpoint** of the transaction and (2) the **script bytes preceding the Sigma tape**. The signature therefore cannot be copied onto a different script or replayed in a different transaction unchanged. + +Sigma supports two signing algorithms: `BSM` (Bitcoin Signed Message — publicly verifiable by anyone who knows the signer's address) and `BRC77` ([BRC-77](../peer-to-peer/0077.md) message signing — using derived child keys and an embedded signer public key, supporting both public verification and private verification by a designated recipient). This document specifies the on-output layout, the signed message construction, and verification for both algorithms. + +## Motivation + +Detached signatures over metadata alone — including AIP ([BRC-302](./0302.md)) signatures, which cover only push-data content — can be replayed onto counterfeit outputs or different transactions. Sigma addresses replay by signing a hash derived from transaction context (an input outpoint) together with the output script content preceding the signature, so the seal travels only with that script in that transaction. Sigma was inspired by AIP and serves the same authorship-attestation role for use cases that additionally require transaction binding, such as issuer-signed token mints. + +## Specification + +The key words "MUST", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. + +### 1. Placement on the Output + +Sigma is appended to the **locking script** of the signed output as a [BRC-300](./0300.md)-style protocol tape, identified by the UTF-8 string `SIGMA` (a string identifier per BRC-300 §1.1): + +``` + +OP_RETURN // or "|" if OP_RETURN is already present + SIGMA + +
+ + +``` + +Rules: + +- The Sigma tape MUST live in the OP_RETURN data path of the locking script. +- If the script has no prior `OP_RETURN`, the tape MUST begin with `OP_RETURN`, then `SIGMA`. +- If the script already has an `OP_RETURN` (for example a MAP tape, [BRC-303](./0303.md)), the Sigma tape is appended with a `|` separator push (`0x7c`), then `SIGMA` — not a second `OP_RETURN`. +- Multiple Sigma instances MAY appear on one output as successive `|`-separated `SIGMA` segments. Instances are indexed 0-based in order of appearance — for example, a user signature followed by a platform signature. + +### 2. Fields (after `SIGMA`) + +| Order | Field | Encoding | Meaning | +|-------|-------|----------|---------| +| 1 | algorithm | UTF-8 push | `BSM` or `BRC77` (Section 4) | +| 2 | address | UTF-8 push | P2PKH address derived from the signer's public key. When signing with an on-chain identity (for example a BAP identity), this is derived from the identity's current signing key. | +| 3 | signature | binary push | Signature bytes; format depends on the algorithm (Section 4). Displayed in hex within scripts; commonly represented in Base64 off-chain. | +| 4 | vin | UTF-8 push of a decimal integer, optionally `-1` | Index of the transaction input whose outpoint is bound into the signature, or `-1` for self-reference (Section 3.1). | + +Verifiers that do not implement an algorithm MUST treat those instances as invalid for any rule that requires a valid Sigma. + +### 3. Signed Message Construction + +Both algorithms sign the same 32-byte message hash, built from an input outpoint and the target output script. + +#### 3.1 Input Hash + +Let `vin` be the field value, where `-1` resolves to the index of the **target output** (the output carrying this tape). Self-reference is used when the tape must be built before the anchor input's final position is known, such as while signing a partially built transaction. Parsers MUST accept a leading `-`, values are not limited to one digit, and verifiers MUST resolve `-1` before computing the hash. + +Let `I` be the transaction input at the resolved index: + +``` +outpoint_bytes = txid_bytes(32) || vout_uint32_le(4) +input_hash = SHA256(outpoint_bytes) +``` + +`txid_bytes` MUST be the 32 bytes obtained by hex-decoding the transaction id **as it is written and displayed**. This is the reverse of the order in which a transaction serializes that txid in its inputs; implementations that hold the txid as a raw hash or read it from a serialized outpoint MUST reverse those 32 bytes before hashing. `vout_uint32_le` is the source output index as a 4-byte little-endian unsigned integer. + +#### 3.2 Data Hash + +Let `S` be the full locking script of the target output. Find the `OP_RETURN` or `|` separator immediately before the `SIGMA` push for **this** instance (by 0-based instance index). Let `prefix` be the script bytes **strictly before** that separator: + +``` +data_hash = SHA256(prefix) +``` + +The separator and the Sigma tape itself are never included in `prefix`. Changing only bytes after the separator (the Sigma fields themselves) is outside the signed prefix by design, which is what allows a placeholder tape to be replaced by the real signature without altering the covered content. + +#### 3.3 Message Hash + +``` +message_hash = SHA256( input_hash || data_hash ) +``` + +(32-byte input hash concatenated with 32-byte data hash, hashed once with SHA-256.) + +An instance whose `message_hash` cannot be computed — a `vin` that does not resolve to an existing input, including `-1` resolving to an output index with no corresponding input, or a `vin` that is not a decimal integer — is **invalid**. Verifiers MUST NOT treat an instance they could not evaluate as valid. + +### 4. Algorithms + +#### 4.1 `BSM` — Bitcoin Signed Message + +- **Signature format:** 65-byte compact recoverable ECDSA signature (1 recovery byte, 32-byte `r`, 32-byte `s`). +- **Signing:** treat `message_hash` as the message bytes for Bitcoin Signed Message signing (the usual BSM magic prefix and double SHA-256 are applied to those 32 bytes as the payload). +- **Verification:** recover the public key from the compact signature and `message_hash` under BSM; the instance is valid if and only if the recovered key's P2PKH address equals the `address` field. +- Anyone who knows the signer's address can verify. + +#### 4.2 `BRC77` — BRC-77 Message Signing + +- **Signature format:** the complete [BRC-77](../peer-to-peer/0077.md) signed-message envelope, pushed as binary. The envelope embeds the signer's identity public key, the verifier scope, the key derivation identifier, and the ECDSA signature, per BRC-77. +- **Signing:** sign the 32-byte `message_hash` as the BRC-77 message payload with the signer's identity private key. The signer MAY designate a specific verifier public key, in which case only that recipient can verify (private verification); omitting the verifier produces a publicly verifiable signature ("anyone" scope, per BRC-77). +- **Verification:** verify the envelope over `message_hash` per BRC-77 (supplying the recipient private key when the signature was scoped to a specific verifier). Verifiers MUST additionally check that the identity public key embedded in the envelope corresponds to the `address` field; an instance whose embedded key does not match the claimed address is invalid. +- BRC-77's use of derived child keys ([BRC-42](../key-derivation/0042.md)/[BRC-43](../key-derivation/0043.md)) means each signature uses a unique signing key while remaining verifiably bound to the signer's identity key. + +### 5. What Is Bound + +A valid Sigma instance asserts that the holder of the key behind `address` authorized: + +- the **specific input outpoint** at the resolved `vin`, and +- the **script content before the Sigma tape** on the target output (inscription, MAP data, locking code, etc.). + +Changing the covered script content, or moving the tape onto another script or transaction, invalidates the signature. + +### 6. Signing Flow for Partially Built Transactions (Informative) + +Wallets commonly: + +1. Build the output script with a **placeholder** Sigma tape (fixed-length zero signature) so transaction fees are stable. +2. Choose an anchor input outpoint (or use `-1` self-reference). +3. Compute the real signature over the outpoint and script prefix, and replace the placeholder. + +Only the final on-chain tape and the verification rules above are normative. + +## Test Vectors + +A `BSM` instance on a MAP-bearing output, so the tape is reached through a `|` separator rather than directly after `OP_RETURN`. + +**Inputs** + +| | | +|--|--| +| Private key (test only) | `0000000000000000000000000000000000000000000000000000000000000001` | +| Signer address | `1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH` | +| Source txid (hex-string order) | `9a1b3c5d7e9f0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293` | +| Source output index | `1` | +| `vin` field | `"0"` (input 0 is the source outpoint above) | + +**Signed prefix** — the script bytes before the `|` push, i.e. a P2PKH lock, `OP_RETURN`, then MAP `SET app brc307` (the app value is arbitrary content; these exact bytes are what the vector's signature covers): + +``` +76a914751e76e8199196d454941c45d1b3a323f1433bd688ac6a223150755161374b3632 +4d694b43747373534c4b79316b683536575755374d74555235035345540361707006627263333037 +``` + +**Intermediate hashes** + +``` +input_hash 33dd9d77bce09fc606a55046fe025776b73f2f2698937a6516fce470d7d499cd +data_hash affa6b6ac6e6f9e4f7385530954b8fb47506333a00f429ca42fa997b52a3a3ad +message_hash bb4fe4baf2fc1344dd64dac57e11d4562606e14de7f4bad0c10d092d86bd537a +``` + +**Signature** (65-byte compact, as pushed into the tape): + +``` +206aa1a3725a012bfe3c497c2cf04c3f93af40dbb9a55d463fe4679d1a9351054a +3db2c0bd3e114786889530b83e3e6c466bafa710f4aaf8cca6cc758bb86c726d +``` + +**Full locking script** — signed prefix, `|`, then `SIGMA BSM
"0"`: + +``` +76a914751e76e8199196d454941c45d1b3a323f1433bd688ac6a223150755161374b3632 +4d694b43747373534c4b79316b683536575755374d74555235035345540361707006627263 +333037017c055349474d410342534d22314267475a3974634e34726d394b427a446e374b70 +72517a3837535a323653414d4841206aa1a3725a012bfe3c497c2cf04c3f93af40dbb9a55d +463fe4679d1a9351054a3db2c0bd3e114786889530b83e3e6c466bafa710f4aaf8cca6cc75 +8bb86c726d0130 +``` + +Two negative checks, both of which have been real implementation errors: + +- Hashing the txid in the transaction's serialization order instead of hex-string order yields a different `input_hash`, and this signature does not verify. +- Using a double SHA-256 for `message_hash` yields a different message, and this signature does not verify. + +## Security Considerations + +- **Replay** — without input and script binding, metadata signatures can be copied onto counterfeit outputs; Sigma exists to prevent that for the signed prefix. +- **vin choice** — signers MUST bind an input they control; verifiers MUST use the `vin` field from the tape, resolving `-1` to the target output's index. +- **Instance index** — when multiple Sigma tapes exist, each is verified with its own instance index for locating `prefix`. +- **Address binding** — for `BSM`, a mismatched network or address encoding fails verification; for `BRC77`, the embedded-key-to-address check in Section 4.2 is what binds the envelope to the claimed identity. +- **Private verification** — a `BRC77` signature scoped to a specific verifier cannot be verified by third parties; applications MUST NOT rely on privately scoped signatures for rules that third parties need to evaluate. + +## Implementations + +Sigma signing and verification are deployed in production wallets, indexers, and token systems; open-source libraries exist in multiple languages. The canonical specification is maintained at https://github.com/opldotdev/sigma. + +## References + +- Sigma repository (canonical specification): https://github.com/opldotdev/sigma +- [BRC-300: Bitcom](./0300.md) — protocol tape and pipe conventions; string identifiers +- [BRC-302: AIP — Author Identity Protocol](./0302.md) — the detached-metadata signature scheme that inspired Sigma +- [BRC-303: MAP — Magic Attribute Protocol](./0303.md) — attribute data commonly covered by Sigma signatures +- [BRC-77: Message Signature Creation and Verification](../peer-to-peer/0077.md) — the `BRC77` algorithm +- [BRC-42](../key-derivation/0042.md) / [BRC-43](../key-derivation/0043.md) — key derivation underlying BRC-77 diff --git a/scripts/README.md b/scripts/README.md index 1dd609c..a286249 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -15,3 +15,8 @@ BRC | Standard 47 | [Bare Multi-Signature](./0047.md) 48 | [Pay to Push Drop](./0048.md) 106 | [Bitcoin Script ASM Format](./0106.md) +300 | [Bitcom — Universal Bitcoin Computer: Decentralized Protocol Registry and Composition](./0300.md) +301 | [B — Bitcoin Data Protocol](./0301.md) +302 | [AIP — Author Identity Protocol](./0302.md) +303 | [MAP — Magic Attribute Protocol](./0303.md) +304 | [Sigma — Transaction-Bound Script Signatures](./0304.md) diff --git a/tokens/0306.md b/tokens/0306.md new file mode 100644 index 0000000..0f7914d --- /dev/null +++ b/tokens/0306.md @@ -0,0 +1,177 @@ +# BRC-306: 1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +**1Sat Ordinals** is a simple way to use a **1-satoshi output** as a non-fungible token and follow that token through the blockchain. + +Each token has a stable id — its **origin** — the outpoint where the 1-satoshi chain started. The token's current location is the **unspent** 1-satoshi outpoint of that chain. When you spend that output into a new 1-satoshi output in the right place in the transaction, the token moves and the origin stays the same. + +## Motivation + +Bitcoin SV allows outputs of exactly one satoshi. A single satoshi is already discrete and transferable; 1Sat Ordinals just names it and tracks it. + +This document standardizes four ideas: + +1. A **token** is a chain of 1-satoshi outputs. +2. **Origin** is the permanent name of that chain (an outpoint). +3. The token's **current outpoint** is whichever 1-satoshi output in the chain is still unspent. +4. A **transfer** is a spend that puts that satoshi into a new 1-satoshi output under sat ordering. + +Everything else — inscriptions, metadata, names, wallet baskets, marketplaces — can build on this. Those are out of scope here. + +## Ordinal Theory (short summary) + +1Sat transfers use the same sat-assignment rule popularized as **Ordinal Theory**: + +* Think of every transaction as moving a line of individual satoshis from inputs to outputs. +* Read inputs in order; within each input, take its satoshis in order. +* Fill outputs in order; within each output, fill its satoshis in order. +* The first satoshi spent is the first satoshi created, the second spent is the second created, and so on. + +Ordinal Theory also numbers every satoshi from coinbase for rarity and global identity. **1Sat Ordinals does not need those serial numbers.** We only use the ordering rule so everyone agrees which output received which input satoshi. Token identity is the **origin** of a 1-satoshi chain, not a global sat serial. + +## Specification + +### Outpoints + +An **outpoint** points at one transaction output: transaction id + output index. + +String references to outpoints follow [BRC-305](../outpoints/0305.md): the canonical form is `txid_vout` (underscore). A dot-separated form (`txid.vout`) also appears in overlay services and BRC-100 wallet APIs; both denote the same outpoint, and implementations accepting external references SHOULD normalize per BRC-305. + +* `txid` is 64 hex characters; `vout` is a non-negative decimal integer. + +### Token + +A **1Sat token** is a chain of **1-satoshi outputs** linked by transfers. + +* Only outputs with exactly **1** satoshi are part of a chain. +* Any locking script is fine (P2PKH, covenant, marketplace lock, …). This BRC does not care how the coin is locked. +* Files, metadata, or app data in the script are optional extras. They do not create or name the token; the chain does. + +While the token is held, exactly one output in the chain is unspent. That output (and its outpoint) is the token's current location. Spending it is how ownership moves. + +### Origin + +The **origin** is where the chain began: the outpoint of the first 1-satoshi output in that chain. It is the stable id you use in APIs, indexes, and UIs. + +Every 1-satoshi output is either: + +* the next link after a transfer of some earlier 1-satoshi output in a chain, or +* a **new origin** (a brand-new token). + +To learn an unspent 1-satoshi output's origin, start at that outpoint and walk **backward** through transfers until you cannot go further. That starting outpoint is the origin. Transfers never change it. + +When a token is first created, the origin outpoint and the current outpoint are the same. + +### Sat ordering + +As in the summary above: satoshis flow from inputs to outputs in order. The *n*th satoshi consumed by the transaction is the *n*th satoshi produced. + +That is the whole rule. No special opcodes. Transaction shape alone decides where each satoshi lands. + +### Transfer resolution + +Transfer is about **accumulated satoshi counts**, not input or output indexes. A 1-satoshi input can sit at any input index and land at any output index; what matters is "how many sats come before this one?" on each side of the transaction. + +Number every satoshi the transaction consumes from `1` upward (input order, then sats within each input). Number every satoshi the transaction produces the same way (output order, then sats within each output). Satoshi *k* on the input side is the same satoshi as *k* on the output side. + +**To resolve one 1-satoshi input:** + +1. Let `S_in` = total satoshis of all **earlier** inputs, plus 1 for this input's single satoshi. + That is this input's global sat index: `S_in = (sum of values of inputs before it) + 1`. +2. Find the output where the running output total first reaches `S_in`. + Equivalently: skip outputs until the cumulative output value is ≥ `S_in`; that output receives satoshi `S_in`. +3. If that output's value is **1**, the whole output is this satoshi → **transfer**: + * spent outpoint = previous location + * that output's outpoint = new location + * **origin unchanged** +4. If that output's value is **greater than 1**, this satoshi is only part of a larger output → **no transfer**. The chain does not continue here. A 1-satoshi output that never receives a transferred satoshi this way is a **new origin**. +5. If no output reaches `S_in`, the satoshi was paid as fee → **burn**. The chain ends and the token has no further location. + +The same count works in reverse for each 1-satoshi output: compute its global sat index from earlier outputs, find which input satoshi has that index, and check whether that input was a 1-satoshi output in an existing chain. + +### Examples + +**Simple transfer** (token input first; easy to see by eye): + +``` +inputs: + i0 1-sat token 1 sat ← global sat #1 + i1 funding 10_000 sats ← sats #2 … #10001 + +outputs: + o0 1-sat token 1 sat ← sat #1 origin unchanged + o1 payment 4_000 sats ← sats #2 … #4001 + o2 change 5_998 sats ← sats #4002 … #10001 +``` + +**Transfer is about counts, not indexes.** Funding and change can come *before* the token on both sides. Only the running totals have to line up: + +``` +inputs: + i0 funding A 3_000 sats ← sats #1 … #3000 + i1 1-sat token 1 sat ← sat #3001 (input index 1, not 0) + i2 funding B 5_000 sats ← sats #3002 … #8001 + +outputs: + o0 payment 2_000 sats ← sats #1 … #2000 + o1 payment 1_000 sats ← sats #2001 … #3000 + o2 1-sat token 1 sat ← sat #3001 origin unchanged + o3 change 4_999 sats ← sats #3002 … #8001 +``` + +Check: sats before the token input = `3000`, so it is global sat `#3001`. Sats before `o2` = `2000 + 1000 = 3000`, and `o2` has value 1, so `#3001` fills `o2` alone → transfer. +If `o2` were merged into a larger output covering `#3001`, the token would not continue — even if some other output happened to be 1 sat. + +**Two tokens in one transaction:** + +``` +inputs: + i0 token A 1 sat ← sat #1 + i1 token B 1 sat ← sat #2 + i2 funding 10_000 sats ← sats #3 … + +outputs: + o0 token A 1 sat ← sat #1 origin A unchanged + o1 token B 1 sat ← sat #2 origin B unchanged + o2 change 9_998 sats ← from funding +``` + +To move a token, arrange inputs and outputs so that satoshi's global index falls on a 1-satoshi output. Index positions alone never decide it. + +### What this document does not cover + +* Inscription envelopes and on-chain content — specified separately (1Sat Inscription Envelopes) +* Metadata protocols +* Wallet APIs, baskets, or tags +* Proofs that a current outpoint descends from an origin — see [BRC-150](./0150.md) +* Content delivery +* Application rules (collectables, names, markets, locks, …) + +Those may cite this BRC for origin, sat ordering, and transfer. + +## Security considerations + +* **Coin selection** — Do not let ordinary payments spend 1Sat token outputs unless a transfer is intended. +* **Output order** — Builders must fix output order so each token satoshi lands in the intended 1-satoshi output. +* **Claimed origins** — A string that says `origin: …` is not proof. Showing that a current outpoint descends from an origin is a separate problem (indexer or proof format). + +## Implementations + +* [docs.1satordinals.com](https://docs.1satordinals.com) +* [b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack) +* [b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk) + +## References + +1. 1Sat Ordinals — +2. Ordinal Theory — +3. [BRC-36](../outpoints/0036.md) — Format for Bitcoin Outpoints +4. [BRC-45](./0045.md) — Definition of UTXOs as Bitcoin Tokens +5. [BRC-305](../outpoints/0305.md) — Outpoint Content Addressing diff --git a/tokens/0307.md b/tokens/0307.md new file mode 100644 index 0000000..8a10e8d --- /dev/null +++ b/tokens/0307.md @@ -0,0 +1,181 @@ +# BRC-307: 1Sat Ordinals — Inscription Envelopes + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +This BRC defines how **inscriptions** attach content to a [BRC-306](./0306.md) token: an `ord` **envelope** embedded in the locking script of a **1-satoshi** output. + +Together with origin tracking, inscriptions are how 1Sat attaches on-chain files and media to a 1-satoshi token — collectables, documents, app data, and other content-bearing uses. + +## Motivation + +A 1Sat token is a 1-satoshi chain identified by origin. Many applications also want **data** bound to that token — an image, a document, app JSON, and so on. + +Inscriptions put that data in the output script using a small, recognizable envelope. Wallets and indexers can find the envelope, read content type and body, and still follow the token with ordinary 1Sat transfer rules. + +This document standardizes the envelope format and the 1Sat rules for when an inscription is valid and how it relates to origin. + +## Relationship to the token model + +See [BRC-306](./0306.md) for origin, sat ordering, and transfer. + +Inscriptions do **not** replace that model: + +* The token is still the 1-satoshi chain. +* Transfer is still sat ordering into a new 1-satoshi output. +* The envelope is content carried on outputs in that chain (typically at origin, sometimes re-inscribed on later outputs in the chain). + +## Specification + +### Envelope format + +An inscription is an `ord` envelope inside an output script. The usual shape includes a content type and a body: + +``` +OP_FALSE OP_IF + <"ord"> // UTF-8 bytes 6f7264 + OP_1 // field 1: MIME type (UTF-8), e.g. image/png + OP_0 // field 0: body bytes +OP_ENDIF +``` + +Rules: + +* After the `ord` tag, the envelope is a sequence of **field / value pairs**. Field **0** (content body) ends the field list; it is followed by `OP_ENDIF`. +* Each pair is a field tag, then a value (normally one push of bytes). +* **Tag aliases:** a single-byte push of `0x00` or `0x01` is equivalent to `OP_0` or `OP_1` (same field number). Minters typically emit the `OP_*` form; parsers MUST accept both. +* In advanced use-cases, a field MAY appear more than once before the body; that does not invalidate the inscription. When resolving a field's value, the **last** occurrence wins. + +#### Fields + +| Field | Tag | Value | Requirement | +|-------|-----|-------|-------------| +| Content type | `1` | MIME string, UTF-8 (e.g. `image/png`) | MUST when creating inscriptions | +| Content body | `0` | Body bytes (MAY be empty) | MUST (terminates the field list) | + +#### Parent (field 3) + +Field **3**, when present, marks a **parent / child** relationship between inscriptions. This follows the same idea as [Ordinals provenance](https://docs.ordinals.com/inscriptions/provenance.html): the owner of a parent inscription can create **child** inscriptions on-chain in a way others cannot fake, by **spending the parent** when minting the child. + +That pattern is used for collections and other hierarchies (e.g. issuer → collection → items). Children may themselves have children. Burning or otherwise destroying the parent can be used by applications to stop further children that would need to spend it. + +**On 1Sat**, the parent value is the parent's **outpoint** (the 1-sat output that carries the parent inscription), not a BTC-style `txid…iN` inscription id string: + +* **36 bytes** — 32-byte txid + 4-byte little-endian vout (preferred). +* **32 bytes** — txid only; treated as that transaction's output **0**. + +**Same-transaction spend (proof):** +If field 3 is set, the parent outpoint MUST appear as an **input** of the transaction that creates this child inscription output. The spend is the proof: anyone can push arbitrary bytes as field 3, but only someone who can unlock the parent output can spend it into the child mint. + +#### Other fields + +Additional field/value pairs MAY appear before the body. They do not invalidate the envelope. Conforming 1Sat readers MAY ignore unknown fields. Application meaning (e.g. collections) is defined elsewhere. + +#### Placement in the script + +The envelope sits **in the output locking script**. Typical patterns: + +``` + + + OP_CODESEPARATOR +``` + +The spend condition MAY be any locking script: P2PKH is common, but covenants, multi-sig, marketplace locks, and other contracts are all valid. This BRC only requires that the envelope is present and well-formed on a 1-satoshi output; it does not constrain how that output is locked. + +### Push data on BSV + +BSV does not impose the historical 520-byte push cap used on some other networks. A field value or content body MUST be a **single** push. Implementations MUST NOT split one logical value across multiple pushes and concatenate them. + +### Valid 1Sat inscription + +An output is a **valid 1Sat inscription** when all of the following hold: + +1. `satoshis === 1` (it is a 1Sat token output under the core model). +2. The locking script contains a well-formed `ord` envelope as defined above. + +Inscriptions are defined for 1Sat Ordinals: the envelope applies to **1-satoshi** outputs that participate in origin tracking. Multi-satoshi outputs with similar script patterns are outside this BRC. + +### Inscriptions on a 1Sat chain + +An envelope may appear on the **origin** output, on a later output in the same chain, or on both (re-inscription when transferring). + +* Chain identity (origin and transfers) is unchanged by envelopes — see [BRC-306](./0306.md). +* This BRC does **not** say which envelope is "the" content for an application. Collectable NFTs, updatable assets, feeds, and other profiles may select differently; those rules belong in application or content-resolution specs. + +### Inscription id + +Because envelopes live in **outputs** (not input witnesses), an inscription is identified by the outpoint of the output that carries it, written per [BRC-305](../outpoints/0305.md). + +A mint often creates origin and first envelope on the same outpoint; after transfers, the token's current outpoint moves while content may still be addressed by origin or by a specific inscription outpoint, depending on the application. + +### Mint (informative) + +A typical mint creates the origin and inscription together: + +``` +inputs: funding … +outputs: o0 = 1 sat, lock + ord envelope ← new origin + inscription + change … +``` + +Transfers afterward follow [BRC-306](./0306.md) (1-satoshi input → 1-satoshi output under sat ordering). The envelope does not need to be repeated on every output in the chain unless the application re-inscribes. + +### Metadata (MAP) + +Optional application metadata MAY follow the inscription on the same output after `OP_RETURN`, using the **Magic Attribute Protocol** ([BRC-303](../scripts/0303.md), protocol id `1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5`): + +``` + OP_RETURN SET type ord name "…" … +``` + +Do not use `OP_FALSE OP_RETURN` if the output must remain spendable in the usual lock+envelope patterns. + +MAP data is a `SET` command followed by string key/value pushes. For ordinal display metadata, common keys are: + +| Key | Requirement | Meaning | +|-----|-------------|---------| +| `app` | MAY | App that produced the ordinal | +| `type` | SHOULD | `ord` when using this schema | +| `name` | SHOULD when a display name exists | Human-readable name (case-preserving) | + +Further keys and other ways to carry MAP (e.g. as an inscription field) are defined by application BRCs such as the 1Sat Collections BRC (specified separately). Unknown keys MUST be ignored by readers that do not implement them. + +Wallets that surface a display name (e.g. in BRC-100 `customInstructions`) SHOULD take it from MAP `name` when present. + +## What this document does not cover + +* Full MAP opcode encoding — see [BRC-303](../scripts/0303.md) and [BRC-300](../scripts/0300.md) +* Collection schemas and in-envelope MAP field layout — specified separately (1Sat Collections) +* Issuer authenticity — see Sigma ([BRC-304](../scripts/0304.md)) +* Large content via multi-transaction streams / OrdFS +* Wallet baskets, tags, or provenance proofs +* Marketplaces and application-specific locks + +Those may require [BRC-306](./0306.md), this envelope BRC, or both. + +## Security considerations + +* **Content authenticity** — An envelope proves data was in a script at an outpoint; it does not by itself prove the token's current outpoint still descends from that origin (see core tracking and any later proof formats). +* **Parent without spend** — Field 3 alone is not proof of parentage; only spending the claimed parent in the same transaction establishes the link. +* **Large bodies** — Very large pushes affect relay and storage; application limits are out of scope here but implementers should plan for them. +* **Content selection** — Showing the wrong envelope for a given app (e.g. latest vs origin) is an application concern, not fixed by this BRC. + +## Implementations + +* [docs.1satordinals.com](https://docs.1satordinals.com) +* `@1sat/templates` `Inscription` in [b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk) +* [b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack) + +## References + +1. [BRC-306: 1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking](./0306.md) +2. [BRC-305: Outpoint Content Addressing](../outpoints/0305.md) +3. [BRC-303: MAP — Magic Attribute Protocol](../scripts/0303.md) +4. 1Sat Ordinals — +5. Ordinals inscriptions — diff --git a/tokens/0308.md b/tokens/0308.md new file mode 100644 index 0000000..bdfb883 --- /dev/null +++ b/tokens/0308.md @@ -0,0 +1,234 @@ +# BRC-308: 1Sat Ordinal Collections + +Open Protocol Labs (info@opl.dev) + +**Authors:** Luke Rohenaz (luke@opl.dev), David Case (dcase@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +This BRC defines **collections** of 1Sat inscribed ordinals: a **collection** origin inscription and **collection item** inscriptions that reference it. + +The **user-minted** model (wallet / app mints) uses a [BRC-307](./0307.md) envelope on a 1-sat output, **MAP** metadata on the same output after `OP_RETURN`, and **Sigma** for issuer binding. + +**Contract-minted** items link via inscription **parent** (field 3) instead: no publisher is available to sign the item, because the contract is the spender. + +## Motivation + +Markets and wallets group ordinals into collections. Historical docs used MAP `subType` values `collection` / `collectionItem`. This BRC standardizes that MAP model with **Sigma** for issuer-bound membership for user-minted items, and documents how contract mints link items via parent when that path is unavailable. + +## Relationship to other documents + +| Concern | Document | +|---------|----------| +| 1-sat chains | [BRC-306](./0306.md) | +| Envelopes + basic MAP | [BRC-307](./0307.md) | +| Sigma wire format and verification | [BRC-304](../scripts/0304.md) | +| Wallet baskets / P1Sat | specified separately (planned) | +| Historical docs | [1sat-ordinals collections](https://docs.1satordinals.com) | + +## Specification + +This document defines one relationship: whether a given inscription is a **member** of a given collection. There are two ways to establish it, and a reader admits an output as a member if **either** succeeds. + +* **MAP path** — the item declares the collection in MAP and carries a Sigma signature from the collection's issuer. This is the user-minted case, where a publisher signs each item. +* **Parent path** — the item names the collection origin as its inscription parent and **spends** that origin in the mint transaction. This is the contract-minted case: no publisher is available to sign the item, because the contract is the spender, so the spend of the collection origin is itself the authorization. + +Both paths are specified below, followed by the membership rule that reads them. + +### User-minted (MAP + Sigma) + +#### Same-output layout + +Collection and item mints put the inscription and MAP on **one** 1-satoshi output. For user-minted items, MAP follows the envelope after `OP_RETURN` ([BRC-307](./0307.md)). + +**User-minted shape:** + +``` +OP_FALSE OP_IF + "ord" + OP_1 "image/png" + OP_0 +OP_ENDIF + +OP_RETURN + 1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 + SET + type "ord" + name "The Awesome Collection" + subType "collection" + subTypeData "{\"description\":\"…\"}" +| +``` + +**Item (absolute `collectionId`):** + +``` +… +OP_RETURN + 1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 + SET + type "ord" + name "Item #3" + subType "collectionItem" + subTypeData "{\"collectionId\":\"\",\"mintNumber\":3}" +| +``` + +Lock/envelope order may vary as allowed by BRC-307. Collection and item mints on this path MUST carry a Sigma from the issuer, appended after MAP on the same output (`|` bitcom separator). + +#### Collection inscription + +MAP fields: + +| Key | Requirement | Value | +|-----|-------------|--------| +| `app` | MAY | Minting app id | +| `type` | MUST | `ord` | +| `name` | MUST | Collection display name | +| `subType` | MUST | `collection` | +| `subTypeData` | MUST | Stringified JSON (below) | + +**`subTypeData` (collection):** + +| Field | Requirement | Meaning | +|-------|-------------|---------| +| `description` | MUST | Short description | +| `quantity` | MAY | Declared size when known (string per MAP); omit if open-ended | +| `rarityLabels` | MAY | Issuer-defined rarity map (JSON) | +| `traits` | MAY | Issuer-defined trait schema (JSON) | + +Unknown keys are ignored. Inscription body SHOULD be an image type for previews. + +Mint the collection **before** items that reference it (unless using same-tx relative ids below). Strict indexers MUST NOT treat an item as a member if the referenced collection origin does not exist. + +#### Collection item inscription + +MAP fields: + +| Key | Requirement | Value | +|-----|-------------|--------| +| `app` | MAY | Minting app id | +| `type` | MUST | `ord` | +| `name` | MUST | Item display name | +| `subType` | MUST | `collectionItem` | +| `subTypeData` | MUST | Stringified JSON (below) | + +**`subTypeData` (collection item):** + +| Field | Requirement | Meaning | +|-------|-------------|---------| +| `collectionId` | MUST | Collection origin outpoint (see forms below) | +| `mintNumber` | MAY | Position in the set | +| `rank` | MAY | Rank within the set | +| `rarityLabel` | MAY | Label from the collection's scheme | +| `traits` | MAY | Trait instances | +| `attachments` | MAY | Extra linked resources | + +#### `collectionId` forms + +`collectionId` identifies the collection **origin** outpoint. + +1. **Absolute** — an outpoint reference per [BRC-305](../outpoints/0305.md) (`txid_vout`; legacy dot form normalized per that document). +2. **Same-transaction relative** — `_N` where `N` is a decimal output index in **this** transaction (e.g. `_0` if the collection is output 0 of the same mint tx). + +Indexers MUST expand `_N` to `{this_txid}_N` using the item's transaction id before comparing or storing membership. Implementations in 1sat-stack use this rule (`NormalizeRelativeOutpoint`). + +Top-level MAP key `collectionId` (outside `subTypeData`) is **not** used for membership; only `subTypeData.collectionId` under `subType=collectionItem`. + +#### Issuer authenticity (Sigma) + +User-minted collection and item mints use **Sigma** so the signature is bound to this output's script / transaction. + +The collection origin's valid Sigma signer is the **collection issuer**. Item membership on the MAP path requires a valid Sigma on the item from **that same signer** (see [Collection membership](#collection-membership)). + +Sigma wire format and verification are defined in [BRC-304](../scripts/0304.md). + +#### Wallet filing (informative) + +Under the planned P1Sat wallet scheme (specified separately): + +* Basket: `p 1sat ordinals` +* The mint is built with a placeholder Sigma tape and sealed before broadcast +* `customInstructions.name` SHOULD match MAP `name` when present + +### Contract-minted (parent) + +Some items are minted by a **smart contract** rather than a user wallet. Typical constraints: + +* The contract **cannot** emit the same `OP_RETURN` MAP payload, and/or +* There is **no collection-owner Sigma** — the contract (or its consensus rules) is the issuer. + +In that case the on-chain membership link is the [BRC-307](./0307.md) **parent / child** pattern, not MAP `collectionId` after `OP_RETURN`: + +1. The parent is the **collection origin** (the 1-sat collection inscription outpoint). +2. The item mint **spends that parent** as an input. +3. The item inscription includes **field 3 (parent)** set to that outpoint (encoding and spend proof per BRC-307). + +Field 3 without spending the parent is not a valid link. For collection membership via this path, the parent MUST be the collection origin. Authorization is whatever the contract enforces on that spend — not owner Sigma. + +When the contract also needs MAP key/values but cannot use post-envelope `OP_RETURN`, it MAY carry MAP **inside the `ord` envelope** as one more inscription field (same tag/value model as content-type and parent in [BRC-307](./0307.md)): + +* **Field tag** — one push of the MAP protocol identifier `1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5` +* **Field value** — **one** push whose bytes are the full MAP script payload — the same binary script that would appear after `OP_RETURN` for user-minted items (`SET`, then key/value pushes). It is not unrolled into separate envelope-level ops. + +``` +OP_FALSE OP_IF + "ord" + OP_1 + OP_3 // parent (spent as input) + // field tag + // field value: single binary push + OP_0 +OP_ENDIF +``` + +where `mapScript` is, for example, the script encoding of `SET name "Item #3"` (and other keys if desired). On this path MAP is optional display/metadata; membership is the parent spend. + +— identical MAP encoding to the post-`OP_RETURN` form; only the container differs. A field whose tag is the MAP protocol id is decoded by treating the **value bytes** as that MAP script. + +If MAP appears both inside the envelope and after `OP_RETURN` (unlikely in practice), apply the in-envelope MAP first, then merge the `OP_RETURN` MAP on top so later keys override on conflict. + +### Collection membership + +An output is a **member** of a collection if **either** path fully succeeds: + +1. **MAP path** — all of: + * MAP (in-envelope first, then merge `OP_RETURN` on top if both exist) has `subType=collectionItem` and `subTypeData.collectionId` naming the collection origin (including `_N` expansion), and + * the item carries a **valid Sigma** whose signer is the **same** as a valid Sigma signer on the collection origin. + +2. **Parent path** — inscription field 3 names that collection origin and the mint spends that outpoint ([BRC-307](./0307.md)). + +Either path alone is enough. Writers typically use one (MAP + matching Sigma for user-minted items; parent for contract mints). Readers do not require both. + +MAP `collectionId` without a matching collection-issuer Sigma is **not** membership on the MAP path — only a claim. + +## What this document does not cover + +* Full rarity percentage validation — indexer policy +* On-chain royalty enforcement +* OrdFS / streams +* Non-collection MAP subTypes +* (Sigma wire format — [BRC-304](../scripts/0304.md)) + +## Security considerations + +* **False `collectionId`** — anyone can write the string; MAP-path membership also requires valid Sigma from the collection issuer. +* **Parent path** — trust is the spend of the collection origin under contract rules. +* **Order** — items referencing a non-existent collection are not members under strict indexing. +* **Relative ids** — `_N` is only valid in the mint transaction that contains output `N`. + +## Implementations + +* [docs.1satordinals.com](https://docs.1satordinals.com) +* [b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack) — `ParseMAP` / `ParseCollection`, inscription parent, OrdFS parent metadata +* [b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk) — collections actions + Sigma apply (align with this BRC; see SDK plan) + +## References + +1. [BRC-306](./0306.md) — 1Sat core +2. [BRC-307](./0307.md) — Inscriptions and basic MAP +3. [BRC-304](../scripts/0304.md) — Sigma +4. [BRC-305](../outpoints/0305.md) — Outpoint Content Addressing +5. 1Sat Ordinals metadata — diff --git a/tokens/0309.md b/tokens/0309.md new file mode 100644 index 0000000..72775b6 --- /dev/null +++ b/tokens/0309.md @@ -0,0 +1,336 @@ +# BRC-309: BSV-21 Fungible Tokens (JSON / Legacy) + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev), Luke Rohenaz (luke@opl.dev) + +**Contributors:** Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +This document specifies the **legacy JSON wire encoding** of BSV-21 fungible tokens: an `ord` inscription with content type `application/bsv-20`. Token balances live in UTXOs. Each token is identified by the outpoint of its **deploy** output. Two supply models are supported: + +1. **Fixed supply** — the entire supply is created in one deploy output. +2. **Auth (authority)** — deploy creates minting authority; later spends of authority mint new supply. + +**New tokens SHOULD use the binary encoding**, specified separately (BSV-21 Binary). This JSON encoding remains normative so indexers and wallets can support existing inventory. + +## Motivation + +Earlier BSV-20 used ticker-first ("first is first") public minting. That model does not give issuers a stable contract identity or controlled minting. BSV-21 replaces ticker identity with **deploy-outpoint identity** and adds authority-gated minting while keeping a pure UTXO balance model: + +* Parallel spends (no global account ledger). +* Ordinary Bitcoin locking scripts on token outputs. +* Indexers validate per-token balance and authority rules without an account database. + +This JSON form is what mainnet inventory uses today (`"p": "bsv-20"`, content type `application/bsv-20`). It is not the deprecated ticker-based BSV-20 protocol. Script-native issuance and contracts should follow the binary encoding (BSV-21 Binary, specified separately) instead. + +## Relationship to other documents + +| Concern | Document | +|---------|----------| +| **Preferred encoding for new tokens** | BSV-21 Binary (specified separately) | +| UTXOs as tokens (philosophy) | [BRC-45](./0045.md) | +| 1Sat origin and sat ordering | [BRC-306](./0306.md) | +| Inscription envelopes | [BRC-307: Inscriptions](./0307.md) | +| Deprecated ticker BSV-20 | [1Sat docs — BSV-20](https://docs.1satordinals.com/fungible-tokens/bsv20) | + +This BRC does **not** define marketplace locks, overlay topic naming, or BRC-100 basket profiles for tokens. + +Indexers MUST keep supporting this encoding for existing tokens. Token id is the deploy outpoint in both encodings; balances for the same id SHOULD be aggregated across encodings. + +## Specification + +### Token identification + +* A **token id** is the outpoint of the deploy output that created the token. +* The `id` field MUST use the form `_`: 64 lowercase hex txid characters, underscore, non-negative decimal `vout`. +* That same underscore form is the token id everywhere else — APIs, storage, topic names, comparison. A token id is a BSV-21 identifier, not a general outpoint reference, so it does not take the [BRC-36](../outpoints/0036.md) dot form. +* The token id is fixed for the life of the token. Transfers never change it. + +### UTXO model + +BSV-21 balances are carried on transaction outputs. Spending a valid token (or authority) input and creating valid token (or authority) outputs is how supply moves, splits, merges, mints, or burns. Any Bitcoin locking script MAY lock a token output (P2PKH, multisig, covenant, marketplace template, …). + +### Content type and inscription + +JSON BSV-21 fields live in a 1Sat / `ord` **inscription** on the output locking script: + +* Content type MUST be `application/bsv-20`. +* Body MUST be a JSON object. +* Protocol field `"p"` MUST be the string `bsv-20`. + +Inscription envelope rules are defined in [BRC-307: Inscriptions](./0307.md). Unrecognized JSON keys MUST be ignored; only fields defined here affect validity. + +### Relationship to 1Sat Ordinals + +The `ord` envelope is only the **carrier** for the BSV-21 JSON payload. Token identity, transfers, mints, and burns follow the UTXO balance and authority rules in this document — **not** [BRC-306](./0306.md) sat ordering or origin tracking. + +A spend moves tokens because valid value (or authority) inputs fund valid outputs of the same token id. Whether the 1-satoshi lands in a particular output under ordinal theory is irrelevant to BSV-21 admission. + +### Supply models + +#### Fixed supply — `deploy+mint` + +One output creates the token and holds the entire initial supply. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `deploy+mint` | +| `amt` | Yes | Total supply as decimal string, max `2^64 - 1` | +| `dec` | No | Decimal precision 0–18; default 0; **string** integer only | +| `sym` | No | See [Symbol (`sym`)](#symbol-sym) | +| `icon` | No | See [Icon (`icon`)](#icon-icon) | + +```json +{ + "p": "bsv-20", + "op": "deploy+mint", + "amt": "21000000", + "sym": "GOLD", + "dec": "8", + "icon": "abc123…def456_0" +} +``` + +Token id = this output's outpoint. + +#### Authority supply — `deploy+auth` + +Deploy creates **no** token value. The deploy output is the first **authority** UTXO. Later authority spends mint value. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `deploy+auth` | +| `dec` | No | Decimals 0–18, default 0 (string) | +| `sym` | No | See [Symbol (`sym`)](#symbol-sym) | +| `icon` | No | See [Icon (`icon`)](#icon-icon) | +| `amt` | No | **MUST NOT** be present | + +```json +{ + "p": "bsv-20", + "op": "deploy+auth", + "sym": "STABLE", + "dec": "2", + "icon": "abc123…def456_0" +} +``` + +### Deploy display fields + +`sym`, `icon`, and `dec` are optional **deploy-only** display metadata. They are set on `deploy+mint` / `deploy+auth` and inherited for wallets and indexers on all later operations. They MUST NOT appear as required fields on `mint`, `auth`, `transfer`, or `burn`. Missing or malformed display fields do **not** invalidate the deploy or the token id. + +#### Symbol (`sym`) + +| | | +|--|--| +| Presence | Optional on deploy | +| Type | JSON string | +| Meaning | Short human-readable ticker / name for UI | +| Uniqueness | **Not** enforced. Many tokens MAY share the same `sym`. Applications MUST key tokens by deploy outpoint id, never by symbol alone. | + +Empty string and omission are both treated as "no symbol." + +#### Icon (`icon`) + +| | | +|--|--| +| Presence | Optional on deploy | +| Type | JSON string | +| Meaning | Pointer to on-chain image bytes used as the token icon | + +When present, `icon` MUST be an **outpoint** naming the output that holds the image: + +* Format: `_` (64 hex txid, underscore, non-negative decimal `vout`). +* Relative form: `_N` (underscore + decimal vout) MAY be used when the image output is in the **same transaction** as the deploy. Indexers expand this to `_N`. + +The referenced outpoint MUST be one of: + +1. **Inscription** — a 1Sat / `ord` inscription whose body is image (or other display) content ([BRC-307](./0307.md)); or +2. **B protocol** — a B ([BRC-301](../scripts/0301.md), Bitcom `19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`) file output whose payload is the image bytes. + +`icon` is a **pointer only**. It is not embedded image data, not an HTTP(S) URL, and not required for token validity. Wallets resolve the outpoint (e.g. via OrdFS `/content/{outpoint}`) to fetch bytes and content type. If the outpoint is missing, unresolvable, or not image-like, UIs SHOULD fall back to a placeholder; the token remains valid. + +Same-tx example (image inscribed on output 0, token deploy on output 1): + +```json +{ + "p": "bsv-20", + "op": "deploy+mint", + "amt": "1000", + "sym": "TEST", + "icon": "_0" +} +``` + +### Operations after deploy + +#### `mint` + +Creates new supply by spending at least one valid authority input of the same token. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `mint` | +| `id` | Yes | Token id (`txid_vout` of deploy) | +| `amt` | Yes | Amount minted in this output (string uint64) | + +Any number of `mint` outputs MAY be created from a single authority spend. Minted amounts are **created**, not drawn from input balances. + +#### `auth` + +Continues, splits, merges, or transfers minting authority. Does not carry token value. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `auth` | +| `id` | Yes | Token id | +| `amt` | No | **MUST NOT** be present | + +Authority capabilities: + +* **Split** — one auth in → many auth out +* **Combine** — many auth in → one auth out +* **Transfer** — auth to a new locking script +* **End** — spend auth with no replacement auth out (that auth is destroyed; minting for the token ends only when **no** auth outputs remain) + +#### `transfer` + +Moves existing supply. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `transfer` | +| `id` | Yes | Token id | +| `amt` | Yes | Amount in this output (string uint64) | + +#### `burn` + +Explicitly removes supply from circulation. Burn outputs are recorded for supply accounting (mints − burns) but carry **no** spendable token value. Spending a burn output later has no effect on token validation. + +| Field | Required | Description | +|-------|----------|-------------| +| `p` | Yes | `bsv-20` | +| `op` | Yes | `burn` | +| `id` | Yes | Token id | +| `amt` | Yes | Amount burned in this output (string uint64) | + +### Field validation summary + +| Field | Rules | +|-------|--------| +| `amt` | Required: `deploy+mint`, `mint`, `transfer`, `burn`. Prohibited: `deploy+auth`, `auth`. Decimal string of uint64 (max 18446744073709551615). | +| `id` | Required: `mint`, `auth`, `transfer`, `burn`. Format `txid_vout` (valid outpoint). Auto = deploy outpoint for deploy ops. | +| `dec` | Optional on deploy only. String integer 0–18. Default 0. Numeric JSON numbers are **not** valid. | +| `sym` | Optional on deploy only. Display string; not unique. See [Symbol](#symbol-sym). | +| `icon` | Optional on deploy only. Outpoint pointer to an inscription or B-protocol file. See [Icon](#icon-icon). | + +### Validation rules + +Validation is **per token id** within a transaction. Indexers admit or reject outputs; consensus miners do not enforce BSV-21 rules. + +**Deploy** (`deploy+mint`, `deploy+auth`): + +* Always valid as genesis (no token-input check). +* Token id := this output's outpoint. + +**Mint**: + +* Requires at least one valid **authority** input of the same token. +* Mint outputs create supply; they are not paid from transfer-input balances. + +**Auth**: + +* Requires spending a valid authority input of the same token. +* Auth inputs contribute **0** to token balance. + +**Transfer and burn (balance)**: + +* Let `I` = sum of amounts on valid **value** inputs of this token (prior admitted `deploy+mint`, `mint`, or `transfer` outputs — not auth, not burn). +* Let `O_t` = sum of `transfer` output amounts for this token. +* Let `O_b` = sum of `burn` output amounts for this token. +* Admit transfer and burn outputs only when `I >= O_t + O_b`. +* If `O_t + O_b > I`: those outputs are invalid and input tokens are **burned** (no admitted transfer/burn outs from that imbalance). +* If `I > O_t + O_b`: the excess is burned (implicit burn). +* Authority inputs do **not** relax transfer balance checks. Presence of auth does not allow unfunded transfers. +* Burn inputs contribute nothing to `I`. + +**Display metadata:** + +* `sym`, `icon`, and `dec` are set at deploy only (see [Deploy display fields](#deploy-display-fields)). +* Later operations need not repeat them; indexers attach deploy metadata when serving balances. +* Invalid or unresolvable `icon` does not affect balance or authority admission. + +### Locking scripts + +Any valid locking script is allowed. BSV-21 does not constrain spend conditions beyond the inscription fields and the validation rules above. + +### Satoshi value (convention) + +By convention in the 1Sat ecosystem, token outputs often hold **1 satoshi**. That is ecosystem practice for indexing and wallet UX, not a consensus rule of this protocol. Validators MAY apply a 1-sat policy when admitting outputs. + +### Protocol identifier note + +All JSON operations use `"p": "bsv-20"` for backward compatibility. Implementations MUST NOT require `"p": "bsv-21"`. The name **BSV-21** refers to this specification family (deploy-id tokens + auth), not the JSON `p` string. + +## Examples + +### Fixed supply lifecycle + +1. **Deploy** `deploy+mint` with `amt: "10000"`, `dec: "2"` → token `abc…_0` with 10 000 base units (100.00 display). +2. **Split** — spend deploy; two `transfer` outs of 5 000 each. +3. **Pay** — spend one 5 000; `transfer` 4 900 to recipient + 100 change. + +### Auth lifecycle + +1. **Deploy** `deploy+auth` → token `def…_0`, authority at that outpoint. +2. **Mint** — spend auth; outputs: `mint` 1 000 000 + `auth` (continue). +3. **Distribute** — `transfer` splits of the mint output. +4. **Delegate** — spend auth → two `auth` outs (admin A, admin B). +5. **End auth** — spend an auth with no `auth` out; that authority ends. Minting stops only when the last auth is ended. + +### Balance check + +Valid: + +``` +In: 1000 + 500 transfer +Out: 800 + 600 + 100 transfer +``` + +Invalid (all transfer outs rejected; inputs burned): + +``` +In: 500 +Out: 300 + 400 +``` + +## Security considerations + +* **Indexer trust** — validity is not miner-enforced; wallets rely on overlays / indexers that implement these rules. +* **Symbol collision** — `sym` is not unique; always key tokens by deploy outpoint id. +* **Auth compromise** — holder of an authority UTXO can mint unbounded supply until that auth is ended. +* **Over-transfer burn** — creating outputs that exceed inputs burns the inputs; careless tx building destroys balances. +* **Display spoofing** — `sym` is not unique; `icon` is an unauthenticated outpoint claim. Resolve the pointed inscription/B file independently if display integrity matters. + +## Implementations + +* **1sat-stack** — Go template `pkg/template/bsv21`, overlay/lookup `pkg/lookup/bsv21`, parse tag `bsv21` ([b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack)). +* **1sat-sdk** — TypeScript `@1sat/templates` BSV21, `@1sat/actions` deploy/mint/transfer helpers ([b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk)). +* Historical docs and ecosystem references: [docs.1satordinals.com](https://docs.1satordinals.com/fungible-tokens/bsv-21). + +## References + +1. 1Sat Ordinals — BSV-21 — +2. 1Sat Ordinals — BSV-20 (deprecated) — +3. [BRC-36](../outpoints/0036.md) — Format for Bitcoin Outpoints +4. [BRC-45](./0045.md) — Definition of UTXOs as Bitcoin Tokens +5. [BRC-306](./0306.md) — 1Sat core +6. [BRC-307: Inscription envelopes](./0307.md) +7. [BRC-301: B — Bitcoin Data Protocol](../scripts/0301.md) diff --git a/tokens/0310.md b/tokens/0310.md new file mode 100644 index 0000000..037e3aa --- /dev/null +++ b/tokens/0310.md @@ -0,0 +1,320 @@ +# BRC-310: BSV-21 Fungible Tokens (Binary) + +Open Protocol Labs (info@opl.dev) + +**Authors:** David Case (dcase@opl.dev) + +**Contributors:** Luke Rohenaz (luke@opl.dev), Kurt Wuckert Jr. (kurt@opl.dev), Michael Boyd (root@opl.dev), Dan Wagner (dan@opl.dev) + +## Abstract + +**BSV-21 (binary)** is a fungible token protocol for Bitcoin SV. Token balances live in UTXOs. Each token is identified by the outpoint of its **deploy** output. Token data is a fixed **script prefix** of data pushes — readable and constructible in Bitcoin script without parsing JSON. + +Two supply models: + +1. **Fixed supply** — the entire supply is created in one deploy output. +2. **Authority** — deploy creates minting authority; later authority spends mint new supply. + +This encoding is the **preferred path for new tokens**. It succeeds the widely deployed JSON / inscription form of BSV-21 ([BRC-309](./0309.md)), which remains supported. Same deploy-outpoint identity and the same UTXO + authority economics; different wire format, designed so contracts can participate. + +## Motivation + +BSV-21 already proved out deploy-id fungible tokens on mainnet via JSON inscriptions (`application/bsv-20`). That form works for wallets and indexers, but it is a poor fit for Bitcoin script: + +* Building a token output in script means assembling an inscription envelope, quoting JSON, and converting amounts to ASCII decimals. +* Checking a token output means parsing text instead of reading fixed offsets. +* Token ids as hex strings use display byte order — the reverse of the 36-byte outpoint layout in sighash preimages — so even an equality check needs convert-and-reverse. + +Issuers and apps still need what JSON BSV-21 delivered: + +* Stable identity (deploy outpoint, not a global ticker race). +* UTXO balances that split and merge like satoshis. +* Controlled minting when issuers need it. + +Plus one more: data that **covenants and contracts** can build and check in script. A script-native prefix gives that — amount as a script number, id as a preimage-shaped outpoint, outputs as concatenated pushes — without abandoning the token model users already hold. + +Indexers still enforce balance and authority rules off-chain; miners do not. Legacy JSON outputs stay valid and must keep working; this document defines binary fully on its own so implementers do not need the JSON spec to build or validate binary tokens. + +## Relationship to other documents + +| Concern | Document | +|---------|----------| +| UTXOs as tokens (philosophy) | [BRC-45](./0045.md) | +| Outpoint formats | [BRC-36](../outpoints/0036.md) | +| Legacy JSON encoding (existing inventory) | [BRC-309: BSV-21 JSON](./0309.md) | + +This BRC does **not** define marketplace locks, overlay topic naming, or BRC-100 basket profiles. + +### Legacy JSON inventory + +The earlier inscription-based encoding is specified in [BRC-309](./0309.md). It is not required reading for implementing this document. + +* **Indexers and wallets** MUST continue to recognize the legacy JSON encoding so existing token inventory remains usable. +* Token id is the deploy outpoint in both encodings. Outputs of either encoding for the same deploy outpoint are the **same token**; balances MUST be aggregated by that id. +* Authority inputs of either encoding gate minting for that token id. +* Each output validates under the rules of **its** encoding (do not assume identical mint/transfer edge cases across encodings). + +## Specification + +### Wire format + +Every token output begins with: + +``` + OP_2DROP OP_2DROP +``` + +| Element | Encoding | +|---------|----------| +| Tag | Push of UTF-8 `BSV21` (hex `4253563231`) | +| Token id | Push of 36-byte outpoint (32-byte txid + 4-byte little-endian vout), or `OP_0` on deploys | +| `OP_2DROP` | Drops tag and id | +| Amount | Minimally encoded script number (> 0 = value), or `OP_0` for authority | +| Payload | `OP_0` (empty), or a CBOR map (see [Payload](#payload)) | +| `OP_2DROP` | Drops amount and payload | +| Rest | Remainder of the locking script (any valid Bitcoin script — e.g. P2PKH, multisig, covenant, marketplace lock) | + +Rules: + +* All four pushes are always present; empty values use `OP_0`. +* The prefix pushes four values and drops all four, so the remainder of the script runs as if alone. +* A script is a BSV-21 binary token output when the prefix matches this layout (including a valid payload push — `OP_0` or CBOR map). Tag, id, and amount define the role; map **contents** do not affect balance or authority admission. +* The tag push is the only protocol marker. +* A decoder consumes the prefix; everything after it is ordinary locking-script content for whatever spend path the output uses. + +### Token identification + +* A **token id** is the outpoint of the deploy output that created the token. +* On the wire it is **36 bytes**: txid in natural/internal byte order ‖ `uint32` little-endian vout — the same layout as outpoints in sighash preimages. +* Deploy leaves the id field empty (`OP_0`); that output's own outpoint **is** the token id. +* Every later output for the token carries the 36-byte id. +* The token id is fixed for the life of the token. +* For display and APIs, the string form is `_` (64 hex chars in display txid byte order, **underscore** separator, per [BRC-305](../outpoints/0305.md)) — the same form used by the JSON encoding ([BRC-309](./0309.md)), so a token presents identically under either encoding. Converting between 36-byte form and that string reverses the 32 txid bytes only. + +### UTXO model + +Balances are carried on transaction outputs. Spending valid value or authority inputs and creating valid value or authority outputs is how supply moves, splits, merges, mints, or burns. Any Bitcoin locking script MAY lock a token output (P2PKH, multisig, covenant, marketplace template, …). + +### Roles + +Each output's role is determined only by whether the token id is present and by the amount: + +| Token id | Amount | Role | +|----------|--------|------| +| Empty | > 0 | **Deploy (fixed supply)** — entire initial supply in this output | +| Empty | 0 | **Deploy (authority)** — first minting authority; no initial value | +| Present | 0 | **Authority** — minting capability for this token | +| Present | > 0 | **Value** — spendable token balance | + +### Amounts + +* Bitcoin script numbers: minimally encoded, non-negative, little-endian. +* Domain: `0` … `2^64 - 1`. The maximum encodes in nine bytes (eight value bytes + high zero sign byte). +* Amounts above the maximum, negative values, or non-minimal encodings are **invalid**. +* Amount zero marks **authority**, not value. + +### Payload + +* The fourth push MUST be either `OP_0` (empty) or a CBOR map ([RFC 8949](https://www.rfc-editor.org/rfc/rfc8949.html)). +* Encoders SHOULD use deterministic CBOR (RFC 8949 §4.2) when writing a map. +* A non-empty push that is not a CBOR map is **not** a valid BSV-21 binary token output. +* Map contents do not affect balance or authority admission. Defined deploy display keys are specified below; unknown keys are ignored. + +### Deploy display fields + +Optional metadata on the **deploy** output only. Later outputs normally use `OP_0` and inherit display data from deploy. Missing or malformed display fields do **not** invalidate the deploy. These keys have no protocol meaning on non-deploy outputs. Additional keys MAY be defined later. + +#### Symbol (`sym`) + +| | | +|--|--| +| CBOR type | text string | +| Presence | Optional | +| Meaning | Short human-readable ticker / name for UI | +| Uniqueness | **Not** enforced. Applications MUST key tokens by deploy outpoint id. | + +#### Icon (`icon`) + +| | | +|--|--| +| CBOR type | byte string, **4 or 36 bytes** | +| Presence | Optional | +| Meaning | Pointer to on-chain image bytes | + +| Length | Encoding | Meaning | +|--------|----------|---------| +| 36 | 32-byte txid (natural order) ‖ 4-byte little-endian vout | Absolute outpoint | +| 4 | 4-byte little-endian vout only | Same-transaction relative: output index in the **deploy** transaction | + +Indexers expand a 4-byte value by prepending the deploy output's txid, yielding a normal 36-byte outpoint. Any other length is treated as absent. + +The referenced outpoint SHOULD hold image (or other display) bytes — commonly a B protocol file ([BRC-301](../scripts/0301.md), `19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`) or an ordinal inscription. `icon` is a pointer only — not embedded image data and not a URL. Wallets resolve the outpoint to fetch content. Unresolvable icons do not affect token validity. + +#### Decimals (`dec`) + +| | | +|--|--| +| CBOR type | unsigned integer | +| Presence | Optional | +| Range | 0–18; default 0 | + +### Supply models + +#### Fixed supply + +Deploy with empty id and amount > 0. That amount is the entire initial supply held in the deploy output. No authority is created unless a separate authority deploy is used (a token has one deploy outpoint). + +#### Authority supply + +Deploy with empty id and amount 0. That output is the first **authority**. Later spends of authority may create value outputs (mint) and/or further authority outputs. + +### Authority operations + +Authority outputs (id present, amount 0) may be: + +* **Split** — one authority in → many authority out +* **Combine** — many in → one out +* **Transfer** — re-lock to a new script +* **End** — spend without a replacement authority out (that authority is destroyed) + +Minting for the token ends only when **no** authority outputs remain. + +### Value operations + +Value outputs (id present, amount > 0) move existing supply or, when an authority input is present, create new supply (mint). Split and merge are ordinary multi-input / multi-output spends under the balance rules below. + +### Validation rules + +Validation is **per token id** within a transaction. Indexers admit or reject outputs; consensus miners do not enforce these rules. + +**Deploy** (empty id): + +* Always valid as genesis (no token-input check). +* Token id := this output's outpoint. + +**Authority** (id present, amount 0): + +* Valid only when the transaction spends a valid authority of the same token. +* Deploy with amount 0 is the token's first authority. +* Authority inputs contribute **0** to token balance. + +**Value** (id present, amount > 0): + +* If the transaction spends a valid authority for the token: value outputs are valid **without** input balance coverage (mint). +* Otherwise: let `I` = sum of amounts on valid value inputs of this token; let `O` = sum of amounts on value outputs of this token. + * Admit value outputs only when `I >= O` (all value outs for the token, or none — all-or-nothing). + * If `O > I`: value outputs are invalid; input tokens are **burned**. + * If `I > O`: the difference is burned (implicit burn). + +Circulating supply is the sum of admitted unspent value UTXOs. + +**Display metadata:** + +* `sym`, `icon`, and `dec` are set at deploy only. +* Invalid or unresolvable `icon` does not affect balance or authority admission. + +### Locking scripts + +Any valid locking script is allowed after the prefix. This protocol does not constrain spend conditions beyond the prefix fields and the validation rules above. + +### Satoshi value (convention) + +By convention, token outputs often hold **1 satoshi**. That is ecosystem practice for indexing and wallet UX, not a protocol rule. Validators MAY apply a 1-sat policy when admitting outputs. + +## Examples + +### Output scripts + +Fixed supply deploy (P2PKH), metadata in CBOR payload: + +``` +"BSV21" OP_0 OP_2DROP 21000000 OP_2DROP +OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +``` + +Authority deploy: + +``` +"BSV21" OP_0 OP_2DROP OP_0 OP_2DROP +OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +``` + +Value output: + +``` +"BSV21" <36-byte token id> OP_2DROP 5000 OP_0 OP_2DROP +``` + +Authority output: + +``` +"BSV21" <36-byte token id> OP_2DROP OP_0 OP_0 OP_2DROP +``` + +### Fixed supply lifecycle + +1. **Deploy** — empty id, amount 10 000 → token id = this outpoint. +2. **Split** — spend deploy; two value outs of 5 000. +3. **Pay** — spend one 5 000; value 4 900 to recipient + 100 change. + +### Authority lifecycle + +1. **Deploy** — empty id, amount 0 (genesis authority). +2. **Mint** — spend authority; value 1 000 000 + authority (continue). +3. **Distribute** — split the value output. +4. **Delegate** — spend authority → two authority outs (admin A, admin B). +5. **End authority** — spend an authority with no authority out. Minting stops only when the last authority is ended. + +### Balance checks + +Valid transfer: + +``` +In: 1_000 + 500 value +Out: 800 + 600 + 100 value +``` + +Invalid (no authority; outs rejected; inputs burned): + +``` +In: 500 +Out: 300 + 400 +``` + +Implicit burn: + +``` +In: 1_000 +Out: 250 +→ 750 burned +``` + +Mint (authority present; value need not be covered by value inputs): + +``` +In: authority +Out: value 1_000_000 + authority +``` + +## Security considerations + +* **Indexer trust** — validity is not miner-enforced; wallets rely on overlays / indexers that implement these rules. +* **Symbol collision** — `sym` is not unique; always key tokens by deploy outpoint id. +* **Auth compromise** — holder of an authority UTXO can mint unbounded supply until that authority is ended. +* **Over-output burn** — creating value outputs that exceed inputs (without authority) burns the inputs. +* **Display spoofing** — `sym` / `icon` are unauthenticated claims; resolve icon outpoints independently if display integrity matters. + +## Implementations + +* Spec source: `bsv21-binary-docs` on [BitcoinSchema/1sat-ordinals](https://github.com/BitcoinSchema/1sat-ordinals). +* Related experiment: Shrug (`pkg/template/shrug` in 1sat-stack) — similar prefix idea, different tag; **not** interchangeable with tag `BSV21`. +* Target implementations: 1sat-stack overlay/templates and `@1sat/*` (in progress relative to legacy JSON path). + +## References + +1. 1sat-ordinals `fungible-tokens/bsv-21-binary.md` (branch `bsv21-binary-docs`) +2. RFC 8949 — CBOR +3. [BRC-36](../outpoints/0036.md) — Outpoints +4. [BRC-45](./0045.md) — UTXOs as tokens +5. [BRC-309: BSV-21 JSON (legacy)](./0309.md) +6. [BRC-305](../outpoints/0305.md) — Outpoint Content Addressing diff --git a/tokens/README.md b/tokens/README.md index 7ddc5b4..a54794b 100644 --- a/tokens/README.md +++ b/tokens/README.md @@ -16,4 +16,9 @@ BRC | Standard 147 | [1Sat Ordinals Basket Profile for BRC-46 / BRC-100](./0147.md) 150 | [1Sat Provenance Remittance for Basket `1sat`](./0150.md) 156 | [Latched 1Sat Provenance for Basket `1sat`](./0156.md) -226 | [Miner-Enforced Resale-Royalty Covenant Tokens (OP_PUSH_TX)](./0226.md) \ No newline at end of file +226 | [Miner-Enforced Resale-Royalty Covenant Tokens (OP_PUSH_TX)](./0226.md) +306 | [1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking](./0306.md) +307 | [1Sat Ordinals — Inscription Envelopes](./0307.md) +308 | [1Sat Ordinal Collections](./0308.md) +309 | [BSV-21 Fungible Tokens (JSON / Legacy)](./0309.md) +310 | [BSV-21 Fungible Tokens (Binary)](./0310.md) \ No newline at end of file