diff --git a/README.md b/README.md index 100a9bb..218dd46 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,7 @@ BRC | Standard 174 | [Consensus-Unique Name Tokens — Identity Binding and Verified Resolution](./tokens/0174.md) 176 | [BSV-21 — Validity Proofs](./tokens/0176.md) 177 | [Wallet-Enforced Expiry for `noSend` Actions](./wallet/0177.md) +186 | [BAP — Bitcoin Attestation Protocol](./peer-to-peer/0186.md) 190 | [Access Gates for Metanet Rooms](./apps/0190.md) 210 | [Derived Collectibles](./apps/0210.md) 218 | [Chat-Native Command Grammar for the Metanet](./apps/0218.md) diff --git a/SUMMARY.md b/SUMMARY.md index 11501cf..3aed77c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -182,6 +182,7 @@ * [Single-Use Signed Proofs for Request Authentication](./peer-to-peer/0138.md) * [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) +* [BAP — Bitcoin Attestation Protocol](./peer-to-peer/0186.md) * [Animated-QR Air-Gap Transport for Arbitrary Payloads (TKQR1)](./peer-to-peer/0225.md) * [Keyed Content and Conditional Key Release](./peer-to-peer/0369.md) diff --git a/peer-to-peer/0186.md b/peer-to-peer/0186.md new file mode 100644 index 0000000..cc5079c --- /dev/null +++ b/peer-to-peer/0186.md @@ -0,0 +1,306 @@ +# BRC-186: 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 selectively revealing a URN preimage. Public identity activity, repeated hashes, and disclosed preimages can still be correlated. BAP transactions are Bitcom-style OP_RETURN payloads under the prefix `1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT` ([BRC-179](https://github.com/opldotdev/BRCs/blob/codex/brc-179-bitcom/scripts/0179.md)), signed with AIP ([BRC-181](https://github.com/opldotdev/BRCs/blob/codex/brc-181-aip/scripts/0181.md)). + +This document specifies the signed record format, identity-key and URN hash calculations, and the meanings of the `ID`, `ATTEST`, `ALIAS`, `DATA`, and `REVOKE` operations. It documents the ordinary rotation and sequence rules. It does not define a complete identity-history consensus algorithm or encrypted DATA envelope. Application patterns and the historical uniKey recipe are informative. + +## 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-181](https://github.com/opldotdev/BRCs/blob/codex/brc-181-aip/scripts/0181.md)), which provides the signature layer, and extends it with stable identities, key rotation, and an attestation vocabulary. + +### Scope and Prior Art + +This is a codification of the deployed BAP record family, not a replacement for [BRC-52 identity certificates](./0052.md) or [BRC-103 mutual authentication](./0103.md). BRC-52 uses certified encrypted fields and revocation outpoints; BAP uses publicly indexed salted-hash attestations and an on-chain signing-address history. No automatic conversion or equivalence is defined. Application patterns in Sections 5 and 9 are informative. The state-resolution and DATA boundaries below identify what a separate application profile must supply; they are not requirements to deliver software before discussing this proposal. + +## 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-179](https://github.com/opldotdev/BRCs/blob/codex/brc-179-bitcom/scripts/0179.md)) with the protocol prefix `1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT`, signed with AIP ([BRC-181](https://github.com/opldotdev/BRCs/blob/codex/brc-181-aip/scripts/0181.md)): + +``` +1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT +[ID | ATTEST | ALIAS | DATA | REVOKE] +[ID Key | URN Attestation Hash] +[Sequence | Address | Data] +| +15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva +[AIP Signing Algorithm] +[AIP Signing Address] +[AIP Signature] +``` + +Each displayed field is a separate script data push, preceded by the output's `OP_RETURN` data path. Operation names and addresses are UTF-8 text; attestation hashes are 64 lowercase hexadecimal characters, not raw 32-byte pushes. Sequence numbers are nonnegative decimal text. By default all fields are signed, so AIP's optional field indexes are omitted. A verifier MUST require the AIP signature to cover all fields of every BAP record it accepts. Unknown operations and malformed fields MUST NOT update identity or attestation state. + +- 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 secret random string that makes guessing a URN preimage harder; it does not make hash collisions impossible. For newly generated attributes, use at least 128 bits of cryptographically secure randomness. Nonces MUST NOT be reused across identities; create a new random nonce for each attribute. + +Hash the exact UTF-8 bytes of the complete URN, with no newline, case folding, whitespace trimming, or Unicode normalization. Hashes interpolated in later URNs use lowercase hexadecimal text. The legacy schemes do not define escaping for colons inside components; applications exchanging structured values must agree their exact string serialization, and MUST NOT silently rewrite already-attested URNs. + +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 UTF-8 bytes of the Base58Check root-address **text**, as implemented by `MasterID.deriveIdentityKey`. Do not Base58-decode the address before hashing: + +``` +identityKey = base58( RIPEMD160( SHA256( UTF8(rootAddress) ) ) ) +``` + +RIPEMD160 consumes the raw 32-byte SHA-256 result. The outer encoding is plain Bitcoin-alphabet Base58 of the 20-byte result, with no address version or checksum. + +This binds the identity key to the root address, preventing others from claiming the same identity key. Older records used random identity keys. They cannot satisfy this derivation rule and require an explicitly identified historical identity profile; failure of the equation MUST NOT automatically enable a legacy fallback. New identities MUST derive as above. + +The following inherited example illustrates field placement only; its identity key and signature placeholders are not a valid cryptographic vector. 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 hash has a valid signature from an address authorized for the trusted authority when the record was made, and the attestation has not been revoked under the applicable state rules. Rotation alone does not invalidate older attestations. Challenges MUST be fresh and bound to the verifier and intended action; a replayed challenge does not prove current control. The revealed identity and hash can link this interaction to other public records. + +### 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 may be public and is not a secret salt). These hashes do not hide low-entropy candidates from an observer who knows the other components; IPv4 addresses can be enumerated. +- **Assertions** — `urn:bap:assert::`, e.g. asserting ownership of a file by its SHA-256 hash. +- **Consent grants** — `urn:bap:grant::` records a signed consent claim; revoking the grant (`REVOKE`) signals withdrawal but cannot establish that consent was freely given or force deletion of a service's 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", ...} +| + +``` + +The AIP signer MUST be an authorized signing address for the named identity at the record position being evaluated; an unrelated signer cannot publish an authoritative alias for another identity. + +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). +- The DATA push is opaque bytes for this record-format specification. There is no on-wire encryption discriminator defined here. A consumer MUST NOT guess whether bytes are plaintext or encrypted. +- The historical proposal names electrum-ecies traditional two-key encryption with the attester and identity-owner keys, but does not fully specify a portable envelope. Encrypted DATA consumers need an explicitly agreed external profile defining the envelope, encoding and key mapping. A record can have a valid covering AIP signature while its DATA payload is unsupported. + +### 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 ) +``` + +This historical recipe has no canonical field framing, character encoding, image normalization, or interoperable test vector. It MUST NOT be treated as a standardized unique-person identifier. A passport image is not guaranteed secret or random, and hashing does not add entropy or prevent cross-service tracking. + +The historical proposal suggested using NFC passport attributes, keeping privateUniKey secret and sharing uniKey where KYC would otherwise be required. Those suggestions do not establish sufficient entropy, privacy, collision-free framing or a standardized derivation. Implementations MUST NOT claim dictionary-attack resistance merely because an image is included. A deployment needs a separately specified and reviewed derivation/privacy profile. The historical `uniKeyExpirationDate` convention uses the passport expiration and the uniKey as its nonce, which creates a link rather than concealing the association: + +``` +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. + +## Historical signed evidence + +BAP ATTEST transaction [`744a55a8…789c5b`](https://whatsonchain.com/tx/744a55a8637aa191aa058630da51803abbeadc2de3d65b4acace1f5f10789c5b), output 0, is included in the [BRC-181 raw transaction fixtures](https://github.com/opldotdev/BRCs/blob/codex/brc-181-aip/scripts/media/0181-vectors.json). Its AIP signature verifies over the BAP prefix, ATTEST command, attestation hash, sequence text `0` and separating pipe. This verifies historical byte encoding and signing, not the authority of a real-world attestor, an identity's rotation history, revocation ordering or chain inclusion. Identity-history resolution and DATA decryption are outside the claim established by this example. + +## Test Vectors + +This hash-only vector is independently reproducible; it is not a full signed transaction: + +```text +rootAddress = 1WffojxvgpQBmUTigoss7VUdfN45JiiRK +SHA256(UTF8(rootAddress)) = c38bc59316de9783b5f7a8ba19bc5d442f6c9b0988c48a241d1c58a1f4e9ae19 +RIPEMD160(previous bytes) = ba64f76a5b8dc4b8938b52b3e9c6c237c203913d +identityKey = 3bcbMuLoBYTYTXKjthzjwiWze4Eg +attributeURN = urn:bap:id:name:John Doe:e2c6fb4063cc04af58935737eaffc938011dff546d47b7fbb18ed346f8c4d4fa +attributeHash = b17c8e606afcf0d8dca65bdf8f33d275239438116557980203c82b0fae259838 +attestationURN = urn:bap:attest:b17c8e606afcf0d8dca65bdf8f33d275239438116557980203c82b0fae259838:3bcbMuLoBYTYTXKjthzjwiWze4Eg +attestationHash = 31a05fd610cf3902e3ff1effd8fe3a775ad15db6a00a4ed47406ce705f105f73 +``` + +To reproduce the identity calculation with Python 3 standard libraries: + +```python +import hashlib +a = b"1WffojxvgpQBmUTigoss7VUdfN45JiiRK" +h = hashlib.sha256(a).digest() +r = hashlib.new("ripemd160", h).digest() +alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" +n, result = int.from_bytes(r, "big"), "" +while n: + n, digit = divmod(n, 58) + result = alphabet[digit] + result +result = "1" * (len(r) - len(r.lstrip(b"\x00"))) + result +assert result == "3bcbMuLoBYTYTXKjthzjwiWze4Eg" +``` + +The upstream illustrative identity hash differs from this computed result. Its worked attestation example also uses `urn:bap:id:attest:` while its grammar uses `urn:bap:attest:`. They hash to different values; historical records MUST be verified against their actual preimages, not silently converted. + +## State-resolution boundary + +This document specifies signed records, not a new historical consensus rule. +An application resolving identity or attestation state MUST identify the history +policy it uses, including record ordering, competing rotations, destruction, +reorganizations, legacy identity recognition, and whether attestation sequences +are grouped by literal signing address or stable identity across rotation. +These alternatives are not interchangeable; the word “signatory” alone does +not choose between them. + +Without such a policy, a reader can verify a record's syntax and covering AIP +signature, but MUST NOT report an authoritative current identity or revocation +state when those choices affect the answer. Conflicting rotations or equal +highest-sequence ATTEST/REVOKE records are indeterminate in that case; neither +first-seen order nor a locally invented txid tie-break resolves them under this +BRC. Unavailable history is likewise indeterminate. An authorization decision +MUST NOT treat an indeterminate state as successful verification. + +A future state-resolution BRC can define one deterministic policy, including +its relationship to historical records. A DATA encryption profile can likewise +specify the missing byte envelope. Neither requires changing the signed record +layout documented here, and neither is claimed to be specified by this draft. + +## 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 + +The [TypeScript source and protocol document](https://github.com/BitcoinSchema/bap) and [Go source](https://github.com/BitcoinSchema/go-bap) are prior art for the record family and hash calculations. These links are informative; no implementation is the normative authority for behavior left outside this draft. + +## References + +- BAP protocol specification (canonical): https://github.com/BitcoinSchema/bap/blob/master/PROTOCOL.md +- Original repository (historical): https://github.com/icellan/bap +- [BRC-179: Bitcom](https://github.com/opldotdev/BRCs/blob/codex/brc-179-bitcom/scripts/0179.md) — prefix and pipeline conventions +- [BRC-181: AIP — Author Identity Protocol](https://github.com/opldotdev/BRCs/blob/codex/brc-181-aip/scripts/0181.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/README.md b/peer-to-peer/README.md index 290b48c..7f85292 100644 --- a/peer-to-peer/README.md +++ b/peer-to-peer/README.md @@ -19,5 +19,6 @@ BRC | Standard 138 | [Single-Use Signed Proofs for Request Authentication](./0138.md) 141 | [Fountain-Coded Air-Gap Transport for Arbitrary Payloads](./0141.md) 169 | [Universal Handle Addressing and Resolution for the Metanet](./0169.md) +186 | [BAP — Bitcoin Attestation Protocol](./0186.md) 225 | [Animated-QR Air-Gap Transport for Arbitrary Payloads (TKQR1)](./0225.md) 369 | [Keyed Content and Conditional Key Release](./0369.md)