Beersy
BRC-170

Locked Content Header (LCH) — Licensed, Micropayment-Enabled Content

Selling small pieces of digital content, like one song, one page, or one AI training sample, has always meant every seller inventing their own way to encrypt it, price it, prove they had the right to sell it, and hand over a key after payment. That made it hard for one player, app, or wallet to work with content sold by different sellers, and impossible to cleanly combine licensed pieces into something new without losing track of who is owed what.

Ty Everettchanged 28 Aug 202664 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-170 accurately, including what it depends on.

Summary

Why
Sellers of fine-grained digital content each had to invent their own encryption, licensing, and payment scheme, leaving no common way for players, wallets, or derivative works to interoperate.
What
BRC-170 defines the Locked Content Header, a BSV-native file format and licensing protocol that pairs encrypted content with signed ODRL-based offers and licenses.
How
A publisher wraps encrypted content in a signed LCH header naming its media type, encryption method, and one or more ODRL-based acquisition offers; a client picks a supported offer, pays over BSV using a declared payment mechanism, and receives a signed license plus the decryption keys or capability it grants.

What this lets you do

  • Wrap any encrypted file type in one licensable container with a declared media type
  • Define multiple acquisition profiles (fixed price, metered, rental, composition, AI training) per asset
  • Settle one BSV transaction across many rights-holders without chain scanning
  • Chain derivative works to their source licenses using C2PA provenance
  • Release decryption keys per segment for seek-friendly or metered access

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

lch headerlicense/offerencrypted asse

The specification

Abstract

This document specifies the Locked Content Header (LCH), a BSV-native container and licensing protocol for encrypted digital content. An LCH package identifies encrypted bytes, their media type and encryption method, the original rights holders, one or more ways to acquire licensed use, and the evidence needed to enforce or later demonstrate the resulting agreement.

LCH is content-type independent. A conforming application can associate the .lch extension with a general LCH handler, inspect the declared inner media type, choose an acquisition profile it fully supports, make the required BSV payment, receive a signed buyer license and decryption capability, and perform only the actions that license permits. The same mechanism applies to audio, video, fonts, documents, software, datasets, model inputs, and formats defined elsewhere.

The protocol also defines metered range acquisition and composition. A derivative LCH can identify source works through C2PA ingredient assertions, retain their downstream policies, and settle a single BSV transaction containing outputs for multiple rights participants. The same transaction is delivered directly to every Payee system with single-use BRC-29 derivation material, or durably retained for a Payee that explicitly selected the authorized-output settlement profile; conforming implementations do not depend on chain scanning to discover payment.

LCH adopts the W3C ODRL 2.2 Information Model and Vocabulary as its normative rights-expression system. It does not invent a parallel license language. This BRC defines an LCH ODRL Profile only for the small number of actions, constraints, and duties not already covered by ODRL.

Status and scope

This BRC defines one extensible protocol with separately declared acquisition profiles. An application need not implement every profile. It can safely use any profile for which it understands every critical mechanism, ODRL term, action, constraint, and duty required for the requested operation, and it must reject that profile otherwise.

The initial profiles cover:

  1. fixed-price rendering or use;
  2. quantity- or range-metered use;
  3. event-metered access such as a page or play;
  4. time-bounded rental;
  5. composition into a derivative work; and
  6. use as AI or machine-learning training input.

BSV payment is the normative payment scope. BRC-105 is the mandatory single-payee HTTP payment mechanism for a full core implementation. BRC-121, multilateral BSV settlement, raw-key delivery, content-decryption modules, stablecoin settlement, or other mechanisms can be selected only by an acquisition profile that identifies them explicitly.

This BRC does not claim that DRM can prevent every copy after plaintext has been rendered. It standardizes confidentiality before acquisition, license evidence, key delivery, behavior by conforming applications, optional hardened enforcement, and the propagation or settlement of agreed downstream duties.

Motivation

BSV applications already sell fine-grained access to digital content. Tempo encrypts master audio, stores the ciphertext through , and releases a key after a BSV payment. PaperTrade sells authenticated access to individual pages and records an expiring entitlement. Similar systems sell video, data, application interactions, or other resources.

Those applications currently decide independently:

  • how content and offers are identified;
  • whether terms are embedded or linked;
  • how the seller proves authority from the rights holder;
  • whether a payment buys a permanent key, a rental, or one event;
  • how a buyer license is represented and recovered;
  • how seeking and partial acquisition interact with encryption;
  • which actions are permitted after decryption;
  • how a protected file is opened by an operating system or another application;
  • how source licenses propagate into a derivative work; and
  • how one transaction pays several rights participants without requiring them to scan the chain.

The historical Locked Content Header draft placed terms, price, a payment URL, and a whole-file AES key-release flow in one binary prefix. That establishes the central idea but couples immutable content to one seller and one price, gives no portable buyer license, does not identify seller authority, and cannot support independently authenticated range reads or composition.

LCH separates these concerns while keeping the original user experience. A file named song.mp3.lch can open in an LCH-aware player. The player sees that the inner type is audio/mpeg, chooses a supported offer, obtains a license, and plays it. It exposes a raw .mp3 only if the ODRL Agreement permits reproduction or the LCH unwrap action. A DAW can instead acquire a composition profile, record the source as a C2PA ingredient, and export a derivative LCH carrying any required downstream policy.

Design principles

  1. An LCH is actionable by itself. The header contains at least one complete signed offer or enough signed seller contact information to obtain one. It also contains the encrypted payload or one or more exact locators for it.
  2. Storage is not licensing. UHRP identifies and locates one byte string. CHIRP adds verified chunking and range retrieval. LCH defines what encrypted bytes represent and how licensed use is obtained.
  3. An offer is not a license. An ODRL Offer proposes use. Payment and acceptance produce a signed ODRL Agreement in a buyer license.
  4. Terms and mechanisms are independent axes. The requested use, payment protocol, offer placement, encryption method, key-delivery method, and enforcement class are named separately inside an acquisition profile.
  5. Unknown means unsupported. A client never guesses the meaning of an unknown critical extension, ODRL profile, action, constraint, duty, payment method, encryption method, or key-delivery method.
  6. Partial use does not imply whole-content access. The segmented encryption profile supports independently authenticated records and separately releasable key periods.
  7. Composition preserves provenance and obligations. C2PA supplies the provenance graph. ODRL supplies permissions and downstream policy. LCH binds those records to licenses, selections, payments, and keys.
  8. Every Payee controls its settlement evidence. Multilateral payment uses one transaction with multiple outputs. Each Atomic BEEF and remittance is submitted to its Payee system, or to the exact availability and evidence providers that Payee signed before payment.
  9. Wallet consent remains a wallet decision. Applications describe and payments. The wallet controls authorization on its side of the BRC-100 boundary.

Prior art and relationship to other standards

BSV standards

  • BRC-26 defines UHRP content addressing and host discovery.
  • BRC-167 defines CHIRP, a chunked Merkle-object layer above UHRP. LCH does not change its integrity, resolution, or hosting rules.
  • BRC-29 defines the BRC-42-derived outputs and remittance material used by the BSV payment profiles.
  • BRC-77 supplies portable identity-key signatures for LCH objects.
  • BRC-78 supplies the first buyer-bound content-key delivery method.
  • BRC-95 supplies Atomic BEEF transaction transport.
  • BRC-100 supplies the application-to-wallet boundary.
  • BRC-103 and BRC-104 supply mutually authenticated HTTP.
  • BRC-105 supplies the primary BSV HTTP monetization framework.
  • BRC-116 defines wallet permission behavior, including spending authorization. LCH does not override it.
  • BRC-118 can carry large BRC-105 payment bodies.
  • BRC-121 is an optional stateless HTTP 402 mechanism.
  • BRC-224 defines a composable media recipe. A BMF asset or component may itself be the plaintext content of an LCH; BMF timing and LCH licensing are orthogonal.

A contemporaneous proposal, Keyed Content and Conditional Key Release, covers generic encrypt-once conditional key release and key . It does not define LCH offers, ODRL licenses, quantity selection, operating-system containers, C2PA composition, or the multilateral receipt workflow. LCH therefore does not depend normatively on that unmerged proposal, but its registered encryption or key-delivery mechanisms can be used by a future LCH profile if adopted.

External standards

  • ODRL 2.2 defines Policies, Offers, Agreements, Permissions, Prohibitions, Duties, Constraints, Parties, Assets, and profile processing. Its common vocabulary already includes play, display, read, execute, archive, reproduce, extract, aggregate, modify, derive, distribute, present, compensate, nextPolicy, reviewPolicy, and watermark.
  • Readium LCP demonstrates the separation of encrypted resources from a provider-issued license carrying an encrypted content key and usage restrictions.
  • Encrypted Media Extensions and Common Encryption initialization data define browser/CDM integration for protected media. They can be registered as LCH enforcement and encryption mechanisms but are not generic payment or license formats.
  • C2PA 2.4 defines signed provenance, current c2pa.ingredient.v3 ingredient assertions, ingredient relationships, region-of-interest metadata, and composition actions including c2pa.placed, c2pa.mixed, and c2pa.remixed.
  • RFC 8949 defines CBOR and deterministic encoding.
  • NIST SP 800-38D defines AES-GCM authenticated encryption.
  • RFC 8188 and Tink Streaming AEAD provide prior examples of independently authenticated encrypted records.
  • W3C Media Fragments supplies optional semantic selectors for temporal and spatial media ranges.

Terminology

  • Asset: The protected work and one encrypted representation described by asset in an LCH header.
  • Asset ID: The LCH identifier computed from the canonical Asset Body.
  • Header: The canonical CBOR LCH Header Object, whether carried in an .lch container or separately.
  • Acquisition Profile: One offered combination of use policy, offer mode, payment mechanism, key-delivery mechanism, encryption mechanism, and enforcement class.
  • Offer: A signed LCH Offer Object containing an ODRL Offer Policy and commercial mechanisms. It does not grant use.
  • License: A signed buyer-specific LCH License Object containing an ODRL Agreement, fulfilled duties, validity, and any keys or DRM capabilities.
  • Rights interest: A copyright, neighboring right, contractual right, or other identified interest in the Asset.
  • : The BSV authorized to act for a rights interest.
  • Seller: The identity that signs an Offer, either as a Controller or under an Authority Grant.
  • License issuer: The identity that signs and returns a License.
  • Payee: An identity receiving one output in a purchase transaction. A Seller, issuer, Controller, and Payee can be different parties.
  • Settlement profile: The Demand-selected rule that defines which signed evidence satisfies that Demand for License issuance.
  • Delivery provider: A Payee-authorized service that durably retains an exact signed Payment Delivery for later authenticated retrieval by that Payee.
  • Transaction evidence provider: A Payee-authorized service that evaluates the exact transaction under an identified policy and signs its evidenced lifecycle state.
  • Content-encryption key (CEK): A uniformly random secret used by an encryption mechanism.
  • Key period: A contiguous range of encrypted segments opened by one CEK.
  • Selection: The whole Asset or normalized ranges requested for an action.
  • Composition Record: The LCH record that binds C2PA ingredients to source Asset IDs, License IDs, selections, downstream policies, and settlement receipts.
  • Conforming application boundary: The software or protected module inside which plaintext may exist transiently while only licensed actions are exposed.

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as described by RFC 2119 and RFC 8174.

1. Wire format

1.1 LCH file framing

An LCH file consists of:

OffsetLengthValue
044c 43 48 01 (LCH followed by major version 1)
48Header length as an unsigned 64-bit big-endian integer
12variableExactly that many bytes of deterministic CBOR Header Object
followingvariableOptional ciphertext payload

The optional trailing payload is the exact ciphertext described by asset.representation. If it is present, its length and SHA-256 digest MUST match the representation. If it is absent, the representation MUST contain at least one locator. A Header Object can therefore be distributed unchanged either with the payload appended or by itself.

There is exactly one encrypted representation per version 1 Header Object. Publishers that need alternative encryption or packaging create another Header Object over the alternative representation and may use an optional plaintext digest or external work identifier to associate them.

The conventional filename is <original-name>.<original-extension>.lch. Operating systems associate the final .lch extension with an LCH handler. The original filename and authoritative media type are carried in the Asset Body and MUST NOT be inferred solely from the preceding filename extension.

The provisional media type is application/vnd.bsv.lch. It is not asserted to be IANA-registered by this BRC. Protocol messages containing a bare Header Object or another LCH CBOR object use the provisional media type application/vnd.bsv.lch+cbor with a type parameter where useful.

1.2 Deterministic CBOR profile

Every LCH CBOR object MUST satisfy the core deterministic encoding requirements of RFC 8949 section 4.2.1, with these additional restrictions:

  1. map keys MUST be text strings;
  2. duplicate map keys, indefinite-length items, CBOR tags, floating-point values, undefined, and non-shortest integer or length encodings are prohibited;
  3. integers MUST be in the range 0 through 2^64-1 unless a field states a smaller range;
  4. text MUST be valid UTF-8 and Unicode Normalization Form C;
  5. map keys MUST be ordered by the bytewise lexical order of their deterministic CBOR encodings; and
  6. a receiver MUST reject an LCH object whose received bytes differ from re-encoding its data model under these rules.

These rules keep identifiers and signatures independent of implementation map order and avoid the ambiguities of floating-point prices or time values.

1.3 Diagnostic JSON

Diagnostic JSON is non-normative and MUST NOT be signed or used to compute an identifier. It represents CBOR maps and arrays as JSON objects and arrays. A CBOR byte string is represented as { "$bytes": "<unpadded-base64url>" }. An unsigned integer greater than 2^53-1 is represented as { "$uint": "<decimal>" }. All other allowed values use their ordinary JSON representation.

An implementation producing diagnostic JSON SHOULD preserve the field names and array order from the decoded data model. Converting diagnostic JSON back to CBOR requires the schema; strings beginning with a particular prefix have no special meaning.

1.4 Extension processing

Keys in an extensions map and entries in a critical array MUST be absolute IRIs and MUST NOT repeat. A critical entry identifies a profile, mechanism, term, or extension on which correct processing of that object depends. A receiver MUST reject the object or skip the containing acquisition profile if it does not implement every listed critical identifier. It MUST NOT infer semantics from an IRI's spelling.

An unknown extension not listed as critical MAY be ignored for behavior, but its exact bytes remain covered by the enclosing identifier and signature. A non-critical extension MUST NOT weaken or replace a core requirement. New fields outside extensions require a new object version unless the applicable map explicitly allows them.

1.5 Time values and boundaries

Every LCH integer time field is an unsigned Unix timestamp in whole UTC seconds, ignoring leap seconds. ODRL dateTime operands remain XML Schema date-times and are evaluated under ODRL rather than converted in the wire object.

Validity intervals are half-open. notBefore is inclusive and notAfter is exclusive: an object is active exactly when notBefore <= now < notAfter, with a missing upper bound treated as unbounded. expiresAt and recoveryUntil are also exclusive upper bounds. A new transaction can be created only while now < expiresAt; idempotent delivery or recovery can continue only while now < recoveryUntil. An interval whose upper bound is not greater than its lower bound is invalid. Implementations MUST use checked unsigned arithmetic and MUST reject timestamps they cannot represent exactly.

1.6 Endpoint and locator trust

Every operational endpoint and every HTTPS content, policy, terms, or provenance locator MUST be an absolute HTTPS URL without user information or a fragment. HTTP locations returned while resolving UHRP or CHIRP MUST pass the same checks before use. A general-purpose client MUST reject loopback, unspecified, link-local, private-use, carrier-grade NAT, documentation, benchmark, multicast, and otherwise non-public destination addresses after every DNS resolution. It MUST defend against DNS rebinding and impose finite connection, response, body-size, and redirect limits.

Every redirect target MUST be revalidated. Authentication credentials, payment headers, cookies, BRC-103/104 session material, and other bearer material MUST NOT be forwarded across . An endpoint whose peer identity has protocol meaning, including a Seller, Payee, License issuer, or key releaser endpoint, MAY follow only same-origin 307 or 308 redirects. A content or detached-document locator MAY follow at most five redirects after applying these rules.

The authenticated remote identity MUST equal the identity required for its protocol role or be backed by the Authority Grant explicitly permitted for that role. TLS authentication alone does not establish an LCH identity role.

Controlled development deployments MAY opt in to explicitly enumerated local origins. Such an exception MUST be disabled by default, MUST NOT weaken checks for any other destination, and MUST NOT be inferred from a hostname suffix or DNS result.

2. Identifiers and signatures

2.1 Object preimages and IDs

Each identifiable LCH body has a type from this registry:

asset, header, authority, offer, selection, license-request, quote, payment-demand, payment-readiness, payment-authorization, payment-delivery, payment-delivery-retrieval, transaction-evidence, payment-delivery-ack, payment-receipt, license, or composition-record.

For type T, version 1 body B, and deterministic encoding CBOR(B), define:

preimage(T, B) = UTF8("LCH/" || T || "/1") || 0x00 || CBOR(B)
id(T, B)       = SHA-256(preimage(T, B))

The display IRI is:

lch:<type>:sha256:<64 lowercase hexadecimal digest characters>

The 32-byte digest, not its display IRI, is carried in CBOR fields ending in Id unless a field explicitly requires an IRI.

The Asset ID is computed from the asset map alone. Acquisition Profiles can consequently change without changing the Asset ID, while any change to the encrypted representation, declared rights interests, provenance, or composition changes it.

2.2 Signed objects

A Signed Object has this shape:

signed-object = {
  "body": { * tstr => any },
  "signatures": [1* bstr]
}

Each signatures item is a complete BRC-77 serialized signature over preimage(T, body). Header, Authority, Offer, Quote, Payment Demand, Payment Receipt, and License signatures MUST use BRC-77's anyone verifier. The multilateral profile also requires public BRC-77 anyone signatures for its License Request and Payment Deliveries so that every Payee can independently bind the buyer, request, and transaction. A License Request in another profile MAY use the intended issuer as the BRC-77 verifier when that profile requires privately verifiable buyer acceptance.

The signer identity encoded by BRC-77 MUST equal the identity occupying the signer's role in the body. Merely obtaining a valid signature is insufficient: the verifier MUST also validate the authority rules for that object.

An object ID excludes the signatures array. Adding another valid signature therefore does not change the object ID.

2.3 BSV identity Party IRIs and time

A 33-byte compressed BSV identity key K, rendered as 66 lowercase hexadecimal characters, is represented in ODRL as:

lch:identity:secp256k1:<K>

An ODRL Party corresponds to an LCH identity only when this exact IRI decodes to the same valid compressed public key. Display names, attributes, DNS names, and endpoint origins do not substitute for that comparison.

Unless a field explicitly states otherwise, every LCH integer time is the number of whole seconds since 1970-01-01T00:00:00Z, ignoring leap seconds. Implementations MUST reject a time outside the range they can process safely and MUST NOT narrow a CBOR uint through a floating-point representation.

3. Header and Asset Body

3.1 Header shape

lch-header = {
  "lch": 1,
  "asset": asset-body,
  "acquisition": [1* acquisition-entry],
  ? "authority": [* signed-object],
  ? "extensions": { * tstr => any },
  ? "critical": [* tstr],
  "signatures": [1* bstr]
}

acquisition-entry = inline-entry / discovery-entry

inline-entry = {
  "mode": "inline",
  "offer": signed-object
}

discovery-entry = {
  "mode": "discover",
  "usageProfile": tstr,
  "seller": bstr .size 33,
  "endpoint": tstr,
  ? "authorityIds": [* bstr .size 32],
  ? "critical": [* tstr]
}

Header signatures are computed as type header over the Header map with signatures removed. At least one valid signer MUST be a Controller named in the Asset Body or an identity with an unbroken Authority Grant chain permitting publishHeader for this Asset.

Every Header MUST provide at least one acquisition entry. An inline entry carries a complete signed Offer. A discovery entry carries enough immutable information to authenticate and contact the Seller and obtain a signed Offer for the same Asset.

3.2 Asset Body

asset-body = {
  "mediaType": tstr,
  "name": tstr,
  ? "workId": tstr,
  "representation": representation,
  "rights": [1* rights-interest],
  ? "provenance": provenance-reference,
  ? "composition": composition-record-body,
  ? "metadata": { * tstr => any },
  ? "extensions": { * tstr => any },
  ? "critical": [* tstr]
}

representation = {
  "ciphertextDigest": bstr .size 32,
  "ciphertextLength": uint,
  ? "plaintextDigest": bstr .size 32,
  "encryption": { * tstr => any },
  "locators": [* tstr]
}

rights-interest = {
  "interest": tstr,
  "holder": {
    "name": tstr,
    ? "identifier": tstr
  },
  "controller": bstr .size 33,
  ? "metadata": { * tstr => any }
}

provenance-reference = {
  "mediaType": "application/c2pa",
  "digest": bstr .size 32,
  ? "inline": bstr,
  ? "locator": tstr
}

mediaType is the media type after decryption and removal of any encryption-profile framing. name is a safe suggested filename and MUST NOT contain a path separator, NUL, . or .. as a complete path component, or an absolute path. Applications MUST apply their own filename sanitization and MUST NOT write to a path selected by the header without user or application policy.

workId can contain an ISRC, ISWC, DOI, on-chain identifier, publisher identifier, or other IRI. It is descriptive and is not an integrity substitute for the Asset ID.

plaintextDigest is optional. Its presence enables cross-representation matching and post-decryption verification but can reveal that ciphertext contains a known file. Publishers omit it when that disclosure is undesirable.

Every original rights holder known to the publisher MUST be named in rights. Distinct interests SHOULD be separate entries. Music can, for example, name sound-recording, musical-work, performance, and sample interests independently. controller identifies the BSV identity from which seller or issuer authority is verified; it is not by itself a legal adjudication of ownership.

A locator MUST identify the exact ciphertext bytes committed by ciphertextDigest. uhrp://, chirp://, and HTTPS locators are initially recognized. A client MUST verify the digest regardless of transport integrity. Unknown locator schemes are unsupported, not reinterpreted.

4. Authority Grants

An identity not directly named as a Controller proves authority with one or more signed Authority Objects.

authority-body = {
  "version": 1,
  "assetId": bstr .size 32,
  "grantor": bstr .size 33,
  "grantee": bstr .size 33,
  "interests": [1* tstr],
  "capabilities": [1* tstr],
  ? "policyActions": [1* tstr],
  ? "usageProfiles": [1* tstr],
  "notBefore": uint,
  ? "notAfter": uint,
  "mayDelegate": bool,
  ? "remainingDepth": uint,
  ? "revocationOutpoint": tstr,
  ? "revocationMaxAgeSeconds": uint .gt 0,
  "nonce": bstr .size 16,
  ? "critical": [* tstr]
}

The initial capability IRIs are:

FragmentMeaning
#publishHeaderSign and distribute Headers for the Asset
#issueOfferSign Offers within the stated interests, actions, and profiles
#issueLicenseIssue buyer Licenses under an authorized Offer
#releaseKeyDeliver CEKs or DRM capabilities for an authorized License
#receivePaymentBe named as a Payee for the stated interests

The full IRI for fragments defined by this BRC is https://bsv.brc.dev/apps/0170<fragment>.

The Authority Object MUST be signed by grantor. An authority chain is valid only if:

  1. its first grantor is the Controller of every covered interest;
  2. every following grantor equals the preceding grantee;
  3. every link covers the Asset ID, capability, policy action, and usage profile being exercised;
  4. the current time is within every validity interval;
  5. every non-final link permits delegation and respects remainingDepth; and
  6. each revocationOutpoint, if present, is unspent under the revocation semantics used by BRC-52 .

An implementation MUST reject cycles, repeated Authority IDs, chains longer than 16 links, and any attempt to widen a capability, action, profile, interest, or validity interval in a delegated grant.

revocationOutpoint and revocationMaxAgeSeconds MUST either both be present or both be absent. revocationMaxAgeSeconds MUST NOT exceed 86,400. The BRC-52 all-zero disabled sentinel MUST NOT be used; an Authority that is not revocable omits both fields.

For each revocable Authority, the verifier MUST query a configured BSV transaction-status source and bind the result to the selected BSV network, the observed chain or block height, and an observation time. The source MUST be either a locally validated chain tracker or an explicitly configured trusted service whose authenticated response is retained as verification evidence. Where the source returns BEEF, , headers, or equivalent proof material, the verifier MUST validate it rather than trusting descriptive status text. The result is one of unspent, spent-mempool, spent-confirmed, or unknown. Only an unspent observation whose age is no greater than revocationMaxAgeSeconds is acceptable. The other states fail closed. A mempool spend makes the Authority temporarily unusable; if that spend disappears, a fresh unspent result can make it usable again. A reorganization invalidates cached observations affected by the changed chain. An offline verifier MAY rely on a cached result only while it remains fresh by these rules.

Spending an Authority's prevents future exercise of that Authority. It does not revoke Licenses already validly issued under it; License revocation remains governed by the Agreement and its enforcement mechanism.

An Offer involving several independently controlled interests MUST provide a valid chain for each required interest. Naming a rights holder without proving the relevant seller authority is not sufficient.

5. Normative ODRL rights model

5.1 Adoption of ODRL

LCH Policies MUST conform to the ODRL 2.2 Information Model and ODRL 2.2 Vocabulary and Expression. The LCH ODRL Profile identifier is:

https://bsv.brc.dev/apps/0170#odrl-profile

An Offer Policy MUST have @type equal to Offer, identify its Seller as assigner, target the LCH Asset IRI, and include the LCH profile identifier. A License Policy MUST have @type equal to Agreement, identify the License issuer or authorized assigner, identify the buyer as assignee, target the same Asset, and include the same profile identifier.

ODRL's default invalid conflict strategy applies. An LCH policy MUST NOT select perm or prohibit; an explicit conflict or a conflict produced by inheritance makes the acquisition profile unusable.

5.2 Policy bytes

An LCH Policy Reference has this shape:

policy-reference = {
  "mediaType": "application/ld+json",
  "digest": bstr .size 32,
  ? "inline": bstr,
  ? "locator": tstr
}

At least one of inline and locator MUST be present. When both are present, they MUST resolve to identical bytes. The bytes MUST be UTF-8 JSON-LD, without a byte-order mark, and their SHA-256 digest MUST equal digest before JSON or JSON-LD processing.

The policy SHOULD use http://www.w3.org/ns/odrl.jsonld as its ODRL context followed by this LCH context when compact terms are used:

{
  "lchv": "https://bsv.brc.dev/apps/0170#",
  "render": "lchv:render",
  "unwrap": "lchv:unwrap",
  "train": "lchv:train",
  "retainLch": "lchv:retainLch",
  "presentTerms": "lchv:presentTerms",
  "selection": { "@id": "lchv:selection", "@type": "@id" },
  "connectivity": { "@id": "lchv:connectivity", "@type": "@id" },
  "enforcementClass": { "@id": "lchv:enforcementClass", "@type": "@id" },
  "commercialPurpose": "lchv:commercialPurpose",
  "wrapperRequired": "lchv:wrapperRequired",
  "satoshi": "lchv:satoshi"
}

The distinct lchv prefix is intentional. It MUST NOT be changed to lch, because lch: is the opaque identifier scheme used by Asset, Offer, License, Selection, and Party IRIs; declaring it as a JSON-LD prefix would rewrite those identifiers during expansion.

Conforming applications MUST ship the exact ODRL 2.2 and LCH profile contexts they support. They MUST NOT fetch and trust a remote context merely because a policy names its URL. An additional or changed context is an unsupported critical semantic dependency unless its exact digest and semantics are supported by the application.

The policy's transmitted bytes are evidence and are never normalized for hashing or signatures. JSON object order has no policy meaning, but changing it changes the Policy Reference digest and therefore creates a different offer or agreement record.

5.3 Actions

LCH uses existing ODRL actions wherever their semantics fit:

Intended operationNormative ODRL action
transient audio/video renditionodrl:play
static visual renditionodrl:display
reading data or a pageodrl:read
running softwareodrl:execute
non-transient retention or cacheodrl:archive
copyingodrl:reproduce
making a new asset from part of a sourceodrl:extract
including an asset in a collectionodrl:aggregate
modifying the same assetodrl:modify
creating a derivative assetodrl:derive
supplying an asset to third partiesodrl:distribute
public performanceodrl:present
payment or royaltyodrl:compensate duty
downstream policyodrl:nextPolicy duty
showing terms to a recipientodrl:reviewPolicy duty
watermarkingodrl:watermark duty

The LCH ODRL Profile adds these Actions. #render and #train are odrl:includedIn odrl:use; #unwrap is odrl:includedIn odrl:reproduce, which is itself included in odrl:use:

IRI fragmentDefinition
#renderCreate a transient rendition when no more specific ODRL action describes the media type
#unwrapDisclose or save raw plaintext outside the conforming application boundary; included in odrl:reproduce
#trainUse the Asset or selected part as input to training, fine-tuning, evaluation, or adaptation of an AI or machine-learning system
#retainLchDuty to distribute the affected asset only in an LCH wrapper carrying the required policy and Composition Record
#presentTermsDuty to present identified human-readable terms and obtain the acceptance required by the policy before transferring or rendering to another party

An application SHOULD request the most specific action. “Export” is not one action: exporting unchanged plaintext exercises unwrap and normally reproduce; exporting a new work exercises derive; giving it to another party also exercises distribute.

5.4 Constraints and enforcement terms

The LCH Profile adds these left operands:

IRI fragmentRight operand
#selectionAn LCH Selection or its immutable ID
#connectivity#online, #offline, or #either
#enforcementClass#advisory, #conformingApplication, or #protectedModule
#commercialPurposeBoolean
#wrapperRequiredBoolean

ODRL's existing count, dateTime, elapsedTime, meteredTime, percentage, purpose, recipient, systemDevice, spatial, and other constraints SHOULD be used rather than equivalent LCH terms.

An ODRL compensation Duty for BSV MUST have a uid, compensatedParty, and the odrl:compensate Action with an Action refinement whose left operand is odrl:payAmount, operator is odrl:eq, right operand is an xsd:integer, and unit is https://bsv.brc.dev/apps/0170#satoshi. Fractional, negative, fiat-denominated, or floating-point values are invalid in the initial profiles. The compensated Party uses the identity IRI from section 2.3.

Enforcement classes mean:

  • #advisory: terms and evidence are displayed or recorded, but technical restriction is not claimed;
  • #conformingApplication: plaintext remains within an ordinary application boundary and the application exposes only permitted actions; and
  • #protectedModule: key use or rendering is performed by a declared CDM, secure enclave, trusted execution environment, or equivalent protected path.

Watermarking, online checks, device binding, and usage reporting are orthogonal ODRL duties or mechanism extensions, not additional points in this ordering.

5.5 Fail-closed policy processing

For a requested action, a client MUST:

  1. resolve and digest-check the exact Policy bytes;
  2. validate the ODRL Policy and all named ODRL Profiles;
  3. expand any compact Policy properties into their normative atomic Rules;
  4. reject conflicts;
  5. verify that a Permission covers the requested action, Asset, buyer, Selection, and current constraints;
  6. verify every Prohibition and precondition Duty relevant to that Permission;
  7. verify that it implements every action, constraint, operator, Party role, Asset relation, and Duty that can affect the result; and
  8. deny the action if no fully understood Permission grants it.

An unknown acquisition profile is skipped. An unknown critical term inside an otherwise selected profile makes that profile unusable. It does not make other independent acquisition profiles unusable.

5.6 Human-readable terms

Machine policy does not replace prose needed to describe warranties, governing law, attribution form, privacy disclosures, refund policy, or other legal terms. An Offer MAY carry humanTerms, an array of Policy References generalized to any media type and optionally including a BCP 47 language.

A License MUST bind the digest of every human-readable term that the buyer was required to accept. Where #presentTerms applies downstream, the referenced bytes or a digest-verified locator MUST accompany the derivative LCH or transfer workflow.

6. Offers and acquisition entries

6.1 Offer Body

offer-body = {
  "version": 1,
  "assetId": bstr .size 32,
  "usageProfile": tstr,
  "seller": bstr .size 33,
  "licenseIssuer": bstr .size 33,
  "requiredInterests": [1* tstr],
  ? "authorityIds": [* bstr .size 32],
  "policy": policy-reference,
  ? "humanTerms": [* human-term],
  "payment": payment-offer,
  "keyDelivery": key-delivery-offer,
  "enforcement": enforcement-offer,
  "notBefore": uint,
  ? "notAfter": uint,
  "nonce": bstr .size 16,
  ? "extensions": { * tstr => any },
  ? "critical": [* tstr]
}

human-term = {
  "mediaType": tstr,
  "digest": bstr .size 32,
  ? "inline": bstr,
  ? "locator": tstr,
  ? "language": tstr
}

key-delivery-offer = {
  "mechanism": tstr,
  * tstr => any
}

enforcement-offer = {
  "class": tstr,
  ? "mechanism": tstr,
  ? "connectivity": tstr,
  * tstr => any
}

The Offer Object MUST be signed by seller. The Seller and License issuer MUST have valid authority for every requiredInterests entry and every ODRL action granted by the Offer.

The top-level ODRL Offer uid MUST equal the LCH Offer IRI computed from the Offer Body. Because this creates a circular dependency if the final ID is inserted before hashing, the transmitted JSON-LD MUST instead use the literal placeholder IRI lch:offer:self only as that top-level uid value. After the exact Policy bytes have been digest-checked and parsed with the pinned contexts, an evaluator virtually substitutes the computed Offer IRI in its in-memory policy model. It MUST NOT rewrite the transmitted bytes or replace the same string in nested properties, targets, Parties, extension values, or other JSON strings.

The ODRL target MUST be the computed Asset IRI. There is no circularity because the Asset ID excludes acquisition entries.

6.2 Inline offers

An inline Offer is immutable within the Header that carries it. Its price, endpoints, policy digests, seller identity, and validity are committed by both the Offer signature and the Header signature. A publisher changes those details by issuing another signed Header, which may reference the same Asset ID and ciphertext.

6.3 Discovered offers

For mode = discover, the client sends an unsigned or profile-required signed Offer query to endpoint, naming the Asset ID, usageProfile, requested action, and optional Selection. The response MUST be a Signed Offer Object whose Seller equals the discovery entry and whose Asset ID and usage profile match the query.

Discovery permits current prices, temporary quotes, subscriptions, inventory decisions, or seller changes without altering the Asset Body. It does not permit the returned Offer to silently change the Asset or requested use.

6.4 Offer withdrawal

An Offer can expire through notAfter. A Seller MAY also publish a signed withdrawal naming its Offer ID through a status endpoint declared as an extension. Withdrawal prevents new Licenses and does not revoke a License already issued or erase CEKs already delivered.

7. BSV pricing and selections

7.1 Payment Offer

The version 1 Payment Offer below is the normative BSV form. A future non-BSV payment profile, including a stablecoin profile, MUST use a distinct profile and payment-mechanism identifier and define its own asset, unit, precision, settlement finality, proof, refund, and replay semantics; it cannot change the meaning of this map.

payment-offer = {
  "protocol": tstr,
  "endpoint": tstr,
  "asset": "BSV",
  "unit": "satoshi",
  "recoveryPeriodSeconds": uint .ge 86400,
  "pricing": fixed-pricing / unit-pricing / quote-pricing
}

fixed-pricing = {
  "kind": "fixed",
  "requirements": [1* payment-requirement]
}

unit-pricing = {
  "kind": "unit",
  "quantityUnit": tstr,
  "unitSize": uint .gt 0,
  "minimumUnits": uint,
  ? "maximumUnits": uint,
  "requirements": [1* payment-requirement]
}

quote-pricing = {
  "kind": "quote"
}

payment-requirement = {
  "dutyUid": tstr,
  "payee": bstr .size 33,
  "buyer": bstr .size 33,
  "endpoint": tstr,
  "satoshis": uint,
  ? "interest": tstr
}

Every dutyUid MUST identify an ODRL compensate Duty in the Offer Policy. Its compensatedParty MUST correspond to the Payee described by the requirement, and its payAmount MUST equal the amount produced by the LCH pricing calculation. A mismatch invalidates the Offer.

recoveryPeriodSeconds declares how long every Payee and the License issuer will support idempotent completion after a valid payment. There is no implicit default. Offer expiry prevents a new purchase but MUST NOT truncate the recovery period of a transaction validly created before expiry.

For fixed pricing, the purchase total is the sum of satoshis across all requirements. For unit pricing, each requirement's satoshis is the price per unitSize; its amount is multiplied by max(minimumUnits, ceil(quantity / unitSize)). A maximumUnits violation requires a quote or another Offer and MUST NOT be silently capped.

Prices are unsigned integers in . Every amount and computed total MUST fit the BRC-100 SatoshiValue range, and all addition, multiplication, and ceiling operations MUST be checked for overflow before payment. Fiat display values or exchange-rate references MAY appear as non-critical metadata but are never substituted for the committed BSV amount.

If there is one requirement, protocol can be BRC-105 or another supported single-payee mechanism. More than one requirement requires the multilateral profile in section 11 unless a future payment protocol explicitly defines equivalent direct delivery to every Payee.

7.2 Selection

selection =
  { "type": "all" } /
  { "type": "segments", "ranges": ranges } /
  { "type": "bytes", "ranges": ranges } /
  { "type": "pages", "ranges": ranges } /
  { "type": "media-fragment", "value": tstr }

ranges = [1* [start: uint, end: uint]]

Ranges are half-open: start is included and end is excluded. They MUST be sorted, non-empty, non-overlapping, and non-adjacent. A producer MUST merge adjacent or overlapping ranges before signing. Empty ranges and start >= end are invalid.

Where a Policy or another object needs an immutable Selection reference, it uses id("selection", selection) and the corresponding lch:selection:sha256:<hex> IRI under section 2.1.

segments refers to encryption segment indices. bytes refers to plaintext byte offsets. pages refers to a publisher-defined page index beginning at zero. media-fragment uses the W3C Media Fragments syntax and is semantic rather than cryptographic.

When segmented AES-256-GCM is used, a Quote and License for bytes, pages, or a media fragment MUST also carry the exact normalized segment ranges whose keys will be delivered. The issuer rounds outward to decodable boundaries and key periods and discloses the resulting coverage and price before payment. Another encryption mechanism MUST define an equally exact coverage representation in its profile. The client MUST NOT assume that a requested ten-second fragment reveals exactly ten seconds of compressed media.

8. Segmented AES-256-GCM encryption profile

The mandatory core encryption mechanism is:

https://bsv.brc.dev/apps/0170#a256gcm-segmented-v1

8.1 Encryption descriptor

a256gcm-segmented = {
  "algorithm": "https://bsv.brc.dev/apps/0170#a256gcm-segmented-v1",
  "encryptionId": bstr .size 32,
  "plaintextLength": uint,
  "segmentSize": uint .gt 0,
  "segmentCount": uint .gt 0,
  "noncePrefix": bstr .size 4,
  "keyPeriods": [1* key-period]
}

key-period = {
  "keyId": bstr .size 32,
  "firstSegment": uint,
  "segmentCount": uint .gt 0
}

encryptionId, every CEK, and noncePrefix MUST be generated with a cryptographically secure random number generator. Each CEK is exactly 32 uniformly random bytes and MUST NOT be reused for another representation or key period.

The is:

SHA-256(UTF8("LCH key id v1") || 0x00 || CEK)

It is both an identifier and a pre-release digest commitment to the uniformly random CEK. A candidate CEK MUST match its Key ID before decryption is attempted.

The key periods MUST partition segment indices 0 through segmentCount - 1 exactly once, without gaps or overlaps, in increasing order.

For plaintext length P and segment size S:

segmentCount = max(1, ceil(P / S))
ciphertextLength = P + 16 * segmentCount

An empty plaintext therefore has one zero-length encrypted segment carrying only its 16-byte authentication tag.

8.2 Segment encryption

For zero-based segment index i, define:

IV  = noncePrefix || uint64be(i)
AAD = UTF8("LCH A256GCM segmented v1") || 0x00
      || encryptionId
      || uint64be(i)
      || uint64be(segmentCount)
      || uint64be(plaintextLength)
      || keyId

Encrypt the segment with AES-256-GCM under the CEK for its key period, the 12-byte IV, the exact AAD, and a 16-byte authentication tag. The record is ciphertext || tag. The encrypted representation is the concatenation of records in segment order. IV bytes are not stored per record.

For every non-final segment, ciphertext record offset is:

i * (segmentSize + 16)

The final record length is (plaintextLength - segmentSize * (segmentCount - 1)) + 16, including the tag. These equations let a resolver request only records needed for a Selection.

A decryptor MUST authenticate a complete record before releasing any plaintext from it. A tag failure, wrong Key ID, invalid partition, record reordering, truncation, or extra bytes invalidates the representation. An application MAY render authenticated records before unrelated later records arrive, but it MUST identify the content as partial until the requested Selection is complete.

8.3 CHIRP alignment

For a detached ciphertext stored through CHIRP's 4 MiB fixed chunking profile, a publisher that wants one encrypted record per CHIRP SHOULD use a plaintext segment size of 4,194,288 bytes, producing a 4,194,304-byte ciphertext record after the 16-byte tag. Smaller encryption segments can be packed into a CHIRP leaf when lower key-release or seek granularity is more important.

The .lch header framing is not included in the detached ciphertext digest. This prevents the 12-byte container prefix and variable header from shifting CHIRP leaf alignment.

8.4 Other encryption mechanisms

An Acquisition Profile MAY identify another encryption mechanism, including media-native CENC, a hardened DRM package, or a future keyed-content BRC. Its identifier MUST specify exact algorithms, and tag rules, associated data, record layout, random-access behavior, key identifiers, and failure behavior. Merely saying “AES-GCM” is insufficient.

Unknown encryption mechanisms make only the affected acquisition profile unusable.

9. License request and license

9.1 License Request Body

license-request-body = {
  "version": 1,
  "offerId": bstr .size 32,
  "assetId": bstr .size 32,
  "buyer": bstr .size 33,
  "action": tstr,
  "selection": selection,
  "acceptedPolicyDigest": bstr .size 32,
  ? "acceptedHumanTermDigests": [* bstr .size 32],
  "requestNonce": bstr .size 16,
  "createdAt": uint,
  ? "mechanismChoices": { * tstr => tstr },
  ? "critical": [* tstr]
}

The License Request ID is the request's object ID and is the idempotency key for purchase. The selected profile determines whether the request is a public BRC-77 signature, a signature privately verifiable by the issuer, or an authenticated-session object. A BRC-105 plus BRC-78 core purchase MUST identify the buyer and bind the accepted policy digest before payment.

The issuer MUST reject a request whose Asset, Offer, action, Selection, terms digests, validity, or mechanism choices do not match the Offer.

9.2 Availability preflight

Before paying, a client MUST:

  1. validate the Header, Asset ID, Offer, authority, ODRL Policy, and requested Permission;
  2. resolve at least one ciphertext source and verify its declared length;
  3. fetch and digest-verify the whole ciphertext when practical, or verify every storage object and ciphertext record required for the requested Selection;
  4. contact the license endpoint and every Payee endpoint required by the selected payment profile; and
  5. display or make available to wallet policy the exact total, Payees, requested action, Selection, Offer ID, and terms digests.

The initial unpaid request naturally exercises the BRC-105/121 reachability check contemplated by the historical LCH draft. Availability before payment does not prove that the decrypted content is valuable or accurately advertised.

9.3 License Body

license-body = {
  "version": 1,
  "assetId": bstr .size 32,
  "offerId": bstr .size 32,
  "requestId": bstr .size 32,
  "issuer": bstr .size 33,
  "subject": bstr .size 33,
  "issuedAt": uint,
  ? "notBefore": uint,
  ? "notAfter": uint,
  "agreement": policy-reference,
  "selection": selection,
  ? "segmentSelection": { "type": "segments", "ranges": ranges },
  "fulfillments": [* fulfillment],
  "keyGrants": [* key-grant],
  ? "statusEndpoint": tstr,
  ? "extensions": { * tstr => any },
  ? "critical": [* tstr]
}

fulfillment = {
  "dutyUid": tstr,
  "settlementProfile": tstr,
  ? "receiptIds": [1* bstr .size 32],
  ? "authorizationId": bstr .size 32,
  ? "transactionEvidenceId": bstr .size 32,
  ? "deliveryAcknowledgementId": bstr .size 32
}

key-grant = {
  "keyId": bstr .size 32,
  "delivery": tstr,
  "payload": bstr
}

The License MUST be signed by issuer, and the issuer MUST be the Offer's License issuer or have issueLicense authority. subject MUST equal the buyer from the License Request for the initial profiles.

The Agreement Policy MUST target the Asset, identify the subject as assignee, include the selected action and Selection, preserve relevant Prohibitions and downstream Duties, and bind all terms accepted by the buyer. Each fulfilled compensation Duty MUST identify its exact settlement profile and the evidence required by that profile. #receipt-complete-v1 uses one or more Payment Receipt IDs. #authorized-output-v1 uses the Payment Authorization, Transaction Evidence, and Delivery Acknowledgement IDs. Fields from another profile MUST NOT be substituted or combined to weaken the selected profile.

The top-level License Agreement uid uses the literal lch:license:self in transmitted Policy bytes and is interpreted during ODRL processing as the computed License IRI, using the exact digest-check, pinned-context parse, virtual substitution, and no-global-rewrite rule defined for Offers.

If an identical valid payment is resubmitted with the same License Request ID, the issuer MUST return the same License or an equivalent reissued License carrying the same Agreement and key grants. It MUST NOT request another payment. A different request attempting to reuse a payment MUST be rejected.

9.4 Validity, offline use, and revocation

Rental, perpetual use, online checks, offline use, device limits, and revocation are determined by the Agreement and selected enforcement mechanism.

If the Agreement permits offline use for a period, the application MUST NOT require network contact during that period merely as an implementation convenience. A status endpoint can stop future use by a conforming online or protected-module profile, but it cannot recall raw CEKs or plaintext already released. Applications and offers MUST describe that limitation accurately.

10. Payment and key-delivery mechanisms

10.1 BRC-105 single-payee profile

The mechanism identifier is:

https://bsv.brc.dev/apps/0170#brc105-single-v1

The client POSTs the signed License Request to the Offer payment endpoint over BRC-103/104. The server returns the standard BRC-105 402 Payment Required challenge. The client pays the exact one-requirement amount, repeats the same request with x-bsv-payment, and receives the signed License.

The BRC-105 server identity MUST equal the requirement Payee or be covered by a valid receivePayment Authority Grant. The License issuer MUST verify payment before issuing the License. BRC-118 MAY be used where message size requires multipart transport.

If a valid BRC-105 payment was created before the challenge expired, the Payee and License issuer MUST permit idempotent redelivery of the same request and payment until the challenge expiry plus the Offer's recoveryPeriodSeconds. They MUST NOT request a second payment for that License Request during recovery.

10.2 BRC-121 profile

The mechanism identifier is:

https://bsv.brc.dev/apps/0170#brc121-single-v1

The HTTP payment follows BRC-121. Because BRC-121 consumes a payment per request and does not itself define reusable entitlement, the LCH response still MUST be a signed License. A client MUST NOT infer that rereading the protected URL consumes another payment when its License already grants the requested action.

10.3 BRC-78 CEK delivery

The mechanism identifier is:

https://bsv.brc.dev/apps/0170#brc78-key-v1

Each keyGrant.payload is a complete BRC-78 serialized encrypted message from an authorized key releaser to the License subject. Its plaintext is exactly:

keyId (32 bytes) || CEK (32 bytes)

For avoidance of ambiguity, the four serialized BRC-78 version bytes are 42 42 10 33, in that order, as specified by the normative BRC-78 serialization table. An implementation MUST NOT reverse those bytes based on a display convention or non-normative example.

The BRC-78 Key ID and identity keys are carried by BRC-78 itself. After decryption, the recipient MUST compare the embedded Key ID, the License keyId, and the digest-derived Key ID from section 8 before using the CEK.

The key releaser MUST be the License issuer or possess releaseKey authority. A License can contain only the key periods needed for its segmentSelection.

10.4 Raw CEK delivery

The mechanism identifier is:

https://bsv.brc.dev/apps/0170#raw-key-v1

keyGrant.payload is keyId || CEK without another encryption layer. This mechanism is permitted only when the acquisition profile requires an authenticated confidential transport such as BRC-103/104 over correctly validated HTTPS, and the Agreement does not require a stronger buyer or device binding.

Raw delivery is not described as legacy. It is a deliberate lower-enforcement profile. Applications MUST NOT store or log the payload outside the storage behavior permitted by the Agreement.

10.5 DRM-specific delivery

A DRM mechanism can place a CDM license, key-system message, device-bound capability, or other opaque bytes in payload. For such a mechanism, the 32-byte keyId is a mechanism-defined capability identifier rather than necessarily the CEK commitment from section 8. Its mechanism specification MUST define that identifier and state persistence, renewal, release, offline, device, output-protection, and error semantics. LCH does not reinterpret opaque DRM policy.

11. Multilateral BSV settlement

The mechanism identifier is:

https://bsv.brc.dev/apps/0170#brc105-multipay-v1

This profile extends the BRC-105/BRC-29 flow for one atomic transaction with several directly notified Payees.

11.1 Quote and Payment Demands

The License issuer or Offer endpoint returns a signed Quote containing the License Request ID, Offer ID, Asset ID, exact Selection, expiry, exact total, and one signed Payment Demand for every required ODRL compensation Duty.

payment-demand-body = {
  "version": 1,
  "requestId": bstr .size 32,
  "offerId": bstr .size 32,
  "dutyUid": tstr,
  "payee": bstr .size 33,
  "buyer": bstr .size 33,
  "endpoint": tstr,
  "satoshis": uint,
  "derivationPrefix": bstr .size 32,
  "challengeNonce": bstr .size 16,
  "expiresAt": uint,
  "recoveryUntil": uint,
  "settlementProfile": tstr,
  ? "critical": [* tstr]
}

quote-body = {
  "version": 1,
  "requestId": bstr .size 32,
  "offerId": bstr .size 32,
  "assetId": bstr .size 32,
  "selection": selection,
  ? "segmentSelection": { "type": "segments", "ranges": ranges },
  "demands": [1* signed-object],
  "totalSatoshis": uint,
  "expiresAt": uint,
  "recoveryUntil": uint,
  ? "critical": [* tstr]
}

Each Demand MUST be signed by its Payee, bind buyer to the buyer identity in the License Request, name exactly one settlement profile, and use a fresh, single-use derivationPrefix generated or approved by that Payee system. The Quote validator MUST compare every embedded Demand buyer to the signed License Request buyer. The Quote MUST be signed by the License issuer. The Quote total MUST equal the sum of Demand amounts and the ODRL compensation duties. The Quote and every Demand MUST carry the same expiresAt and recoveryUntil. recoveryUntil MUST equal expiresAt + recoveryPeriodSeconds from the Offer, with checked unsigned arithmetic.

The mandatory baseline settlement profile is https://bsv.brc.dev/apps/0170#receipt-complete-v1. A full core implementation MUST support it. A Demand using https://bsv.brc.dev/apps/0170#authorized-output-v1 opts into section 11.5. A client, issuer, or Payee that does not implement the exact selected profile MUST fail closed before transaction creation; it MUST NOT interpret an absent or unknown value as the baseline profile. Settlement profile selection belongs to each Payee because it changes which third-party evidence that Payee authorizes the issuer to rely upon.

Every Demand endpoint is independently chosen or approved by that Demand's Payee. It is not inherited from the Offer payment endpoint, and neither shared origin nor shared operation is implied. The License issuer, a recording controller, a composition controller, and a nested source Payee can therefore expose different endpoint authorities and independently controlled receiving wallets. Co-location at one URL is only a deployment shortcut.

Before creating a transaction, the client MUST contact every Demand endpoint directly and obtain a signed Payment Readiness from that Payee:

payment-readiness-body = {
  "version": 1,
  "demandId": bstr .size 32,
  "requestId": bstr .size 32,
  "payee": bstr .size 33,
  "buyer": bstr .size 33,
  "issuedAt": uint,
  "readyUntil": uint,
  "recoveryUntil": uint,
  ? "critical": [* tstr]
}

The Payment Readiness MUST be signed by the Demand Payee and bind the exact Demand ID, Request ID, Payee, buyer, and recovery deadline. A client MUST require issuedAt <= current-time < readyUntil <= expiresAt and an exact recoveryUntil match. The Payee thereby states that its durable Demand ledger and receiving service are prepared for idempotent delivery through the Demand recovery window. A coordinator's assertion of reachability is insufficient. The client MUST persist every Payment Readiness with the Quote and MUST repeat readiness acquisition if any readyUntil expires before transaction creation.

A Payment Readiness is neither transaction evidence nor a Payment Receipt. It reduces the outage window but MUST NOT satisfy receipt-complete License issuance by itself.

11.2 Transaction construction

This specification distinguishes four transaction lifecycle states:

  1. finalized — signed transaction bytes and their transaction ID exist;
  2. broadcast — an identified network submission service has accepted a request to propagate those exact bytes;
  3. accepted — an identified transaction processor has evaluated and accepted the transaction under a stated policy; and
  4. mined — block inclusion is supported by evidence anchored to an identified chain tip.

An Atomic BEEF proves transaction structure and ancestry sufficient for its verifier; by itself it proves neither broadcast, current processor acceptance, nor block inclusion. A wallet response containing finalized bytes MUST NOT be presented as broadcast, accepted, mined, or simply “paid” without the corresponding evidence. Unless a settlement profile specifies stronger evidence, the multipay construction establishes only the finalized state.

The buyer creates one BSV transaction with one BRC-29 P2PKH output per Demand:

  1. use BRC-29 [2, "3241645161d8"];
  2. use that Demand's derivationPrefix;
  3. for #receipt-complete-v1, generate a fresh unique 32-byte derivationSuffix; for #authorized-output-v1, use only the exact suffix in the valid Payment Authorization;
  4. use the Demand Payee identity as ;
  5. pay exactly the Demand satoshis amount; and
  6. permit the wallet to apply its own output-ordering and privacy policy.

For BRC-29 key derivation and wallet remittance, encode each 32-byte prefix and suffix as unpadded base64url. The BRC-43 Key ID is exactly <base64url-prefix> <base64url-suffix> with one U+0020 space. No other base64 alphabet, padding, hexadecimal representation, or Unicode normalization is permitted in this profile.

All required outputs MUST be in the same subject transaction. Extra unrelated outputs are allowed, but an LCH License issuer and Payees inspect only the Demand-bound outputs. Before asking the wallet to create an authorized-output transaction, the client MUST independently derive the BRC-29 from the authorized prefix, suffix, buyer wallet, and Payee counterparty and compare it byte-for-byte with the Payee-signed script. A mismatch MUST fail before transaction creation. After the wallet finalizes the transaction, the client MUST derive the expected locking script for every Demand and match it, together with the exact amount, against exactly one previously unmatched output. It records that final output index in the Payment Delivery. A missing, duplicate, or ambiguous match is ERR_LCH_PAYMENT. A wallet integration that cannot return the finalized transaction bytes MUST refuse this profile before payment. The transaction is transported as one Atomic BEEF.

11.3 Direct delivery

For each Payee, the client sends a Payment Delivery directly to that Payee's Demand endpoint over the declared authenticated transport:

payment-delivery-body = {
  "version": 1,
  "demandId": bstr .size 32,
  "requestId": bstr .size 32,
  "buyer": bstr .size 33,
  "atomicBeef": bstr,
  "outputIndex": uint,
  "derivationPrefix": bstr .size 32,
  "derivationSuffix": bstr .size 32,
  ? "critical": [* tstr]
}

The Payee MUST verify the Demand, require the Payment Delivery signer and buyer to equal the Demand buyer, and verify the amount, derived locking script, output index, Atomic BEEF, transaction validity under its wallet policy, and single-use prefix before calling its receiving BRC-100 wallet's internalizeAction with protocol wallet payment. The payment remittance contains the unpadded-base64url derivationPrefix, unpadded-base64url derivationSuffix, and hexadecimal buyer identity. When independently deriving the receiving public key through BRC-100, the Payee wallet uses the buyer as counterparty and forSelf: true.

The client MUST persist the Quote, Payment Readiness objects, any Payment Authorizations, finalized Atomic BEEF, every remittance, and every signed Payment Delivery before the first network delivery. It then fans the Deliveries out independently and retains each valid Receipt as it arrives. Under #receipt-complete-v1, completion requires exactly one valid Receipt for every Demand. Under #authorized-output-v1, section 11.5 defines an additional exact evidence that can satisfy only a Demand that selected that profile. A failed or slow Payee delivery MUST NOT cause already successful delivery evidence to be discarded or the transaction to be recreated. The License issuer coordinates completion but is not an implicit payment relay and MUST NOT treat its own unsigned acknowledgement, a timeout, or Payee silence as settlement evidence.

On success it returns a signed Payment Receipt:

payment-receipt-body = {
  "version": 1,
  "demandId": bstr .size 32,
  "requestId": bstr .size 32,
  "payee": bstr .size 33,
  "txid": bstr .size 32,
  "outputIndex": uint,
  "satoshis": uint,
  "receivedAt": uint,
  ? "critical": [* tstr]
}

txid is the 32 bytes obtained by hex-decoding the conventional 64-character transaction ID without reversing its displayed byte order.

Exact redelivery of the same transaction and output for the same Demand MUST return the same Receipt or an equivalent newly signed Receipt. It is an idempotent recovery, not a second use. A different transaction, output, buyer, or request attempting to reuse the Demand MUST be rejected.

The buyer submits the Atomic BEEF and exactly one profile-valid settlement proof for every Demand to the License issuer. Before issuing the License, the issuer MUST independently verify the transaction ID, every required and distinct output index, exact amounts, Demand and Request bindings, required signatures, and evidence IDs. For #receipt-complete-v1, the receiving Payee's signed Receipt attests the BRC-29 locking-script and wallet-policy checks that require its private derivation context; an issuer that is not that Payee cannot reproduce that private derivation. For #authorized-output-v1, the Payee discloses and signs the exact destination before payment, allowing the issuer to verify it under section 11.5. A coordinator cannot omit all profile-valid evidence merely because an output probably exists.

11.4 Failure and recovery

One transaction makes the outputs atomic within the finalized transaction, but direct deliveries can fail independently and the transaction may or may not yet have stronger network evidence. Signed readiness reduces but cannot eliminate that risk. Payee systems and the License issuer MUST accept idempotent recovery while the current time is less than the signed recoveryUntil for a transaction created before expiresAt. No new transaction may be created at or after expiresAt for that Quote. The client MUST retain the Quote, Readiness objects, Atomic BEEF, remittance, signed Deliveries, and successful Receipts until it obtains the License or the recovery deadline passes.

After transaction creation and before License issuance, an application MUST expose an explicit pending-settlement state. It MUST show the strongest evidenced transaction lifecycle state, the settlement profile and received proof type for each Demand, the number of satisfied and required Demands, and the recovery deadline. It MUST NOT collapse a missing proof into a fresh purchase path or describe finalized-only bytes as a completed payment. When the recovery deadline passes without the evidence required by each selected profile, the application MUST surface an unresolved settlement and MUST NOT release key material.

A wallet MUST NOT create a replacement transaction automatically after an ambiguous failure. It first retries delivery and license recovery with the existing transaction.

The v1 transaction and Atomic BEEF do not prove when an unconfirmed transaction was created. A Payee therefore MUST NOT claim that recovery-time acceptance by itself proves pre-expiry creation. The client and wallet remain responsible for the expiresAt creation rule. A deployment that requires independently enforceable creation-time evidence MUST select a future critical commitment or timestamp mechanism that defines that evidence; it MUST NOT infer it from transaction lock time, first HTTP receipt time, or first-seen time.

11.5 Payee-authorized output settlement

The offline-capable settlement profile identifier is:

https://bsv.brc.dev/apps/0170#authorized-output-v1

This profile addresses a narrow availability failure: a Payee was online before payment and explicitly authorized an exact receiving output and independent fallback services, but its wallet or direct Delivery endpoint is unavailable after the one multilateral transaction has been finalized. It does not turn silence, an ordinary output, or issuer observation into Payee consent.

Before transaction creation, the Payee endpoint MUST return this signed object idempotently for the exact Demand:

payment-authorization-body = {
  "version": 1,
  "settlementProfile": "https://bsv.brc.dev/apps/0170#authorized-output-v1",
  "demandId": bstr .size 32,
  "requestId": bstr .size 32,
  "payee": bstr .size 33,
  "buyer": bstr .size 33,
  "satoshis": uint,
  "derivationPrefix": bstr .size 32,
  "derivationSuffix": bstr .size 32,
  "lockingScript": bstr,
  "authorizedAt": uint,
  "authorizedUntil": uint,
  "recoveryUntil": uint,
  "evidenceProvider": bstr .size 33,
  "evidenceEndpoint": tstr,
  "evidencePolicy": "https://bsv.brc.dev/apps/0170#signed-processor-acceptance-v1",
  "minimumTransactionState": "accepted",
  "deliveryProvider": bstr .size 33,
  "deliveryEndpoint": tstr,
  "retrievalEndpoint": tstr,
  ? "critical": [* tstr]
}

The Authorization MUST be signed by payee; bind every repeated field exactly to the Demand; satisfy authorizedAt <= now < authorizedUntil <= expiresAt; and carry the exact Demand recovery deadline. The Payee generates or approves the single-use suffix through its receiving wallet and derives lockingScript under BRC-29 using the Demand buyer as counterparty and forSelf: true. The script MUST be nonempty and no larger than 10,000 bytes. A Payee MUST return the same Authorization for an idempotent repeat of the same Demand and MUST NOT authorize a second destination for it.

The initial evidence policy is #signed-processor-acceptance-v1. It supports exactly the accepted minimum and this object:

transaction-evidence-body = {
  "version": 1,
  "authorizationId": bstr .size 32,
  "txid": bstr .size 32,
  "provider": bstr .size 33,
  "state": "accepted",
  "policy": "https://bsv.brc.dev/apps/0170#signed-processor-acceptance-v1",
  "observedAt": uint,
  ? "critical": [* tstr]
}

The named evidence provider MUST independently parse the exact Atomic BEEF, require exactly one output with the authorized amount and script, evaluate the transaction under its stated processor-acceptance policy, and sign the exact transaction ID and Authorization ID. authorizedAt <= observedAt < recoveryUntil is required. The provider MUST atomically bind an Authorization to the first accepted transaction ID and reject a conflicting transaction for that Authorization. Buyer assertion, wallet finalization, submission for broadcast, and an issuer-created label are insufficient. A future mined-state policy must define and carry verifiable SPV evidence; this v1 policy MUST NOT relabel a provider signature as mined evidence.

Before fallback completion, the buyer MUST submit the exact signed Payment Delivery to the authorized Delivery provider and obtain:

payment-delivery-ack-body = {
  "version": 1,
  "authorizationId": bstr .size 32,
  "deliveryId": bstr .size 32,
  "demandId": bstr .size 32,
  "requestId": bstr .size 32,
  "payee": bstr .size 33,
  "provider": bstr .size 33,
  "storedAt": uint,
  "availableUntil": uint,
  "retrievalEndpoint": tstr,
  ? "critical": [* tstr]
}

The Delivery provider MUST durably store the byte-exact Authorization and buyer-signed Delivery before signing the Acknowledgement, and MUST durably record that signed Acknowledgement before returning it. Its identity and retrieval endpoint MUST equal the Authorization. authorizedAt <= storedAt < recoveryUntil, storedAt < availableUntil, and availableUntil >= recoveryUntil are required. Exact repeated storage returns the same Acknowledgement; conflicting Delivery bytes for the Authorization are rejected.

The Payee retrieves the stored Delivery with a fresh signed request:

payment-delivery-retrieval-body = {
  "version": 1,
  "authorizationId": bstr .size 32,
  "payee": bstr .size 33,
  "requestedAt": uint,
  "nonce": bstr .size 16,
  ? "critical": [* tstr]
}

The request MUST be signed by the Authorization Payee and bind the exact Authorization ID. The provider authenticates that signature and, while `requestedAt < availableUntil`, returns the exact signed Authorization, Delivery, and Acknowledgement. Implementations SHOULD apply authenticated transport and access logging as defense in depth. A native message-box binding MAY satisfy the same durable retrieval role only when its registered profile defines equivalent authentication, retention, correlation, and replay behavior.

An authorized-output evidence bundle is:

```cddl
authorized-output-evidence = {
  "authorization": signed-object,
  "delivery": signed-object,
  "transactionEvidence": signed-object,
  "deliveryAcknowledgement": signed-object
}

The issuer MAY issue the License for an authorized-output Demand without a Payee Receipt only after independently verifying all four objects, their signatures and IDs, the exact completion Atomic BEEF, one distinct authorized output index and amount, all Demand/Request/buyer/Payee bindings, the accepted evidence policy, and retention through recovery. Each Quote Demand MUST be satisfied exactly once: by its valid Payee Receipt, or—only when that Demand selected this profile—by its valid authorized-output bundle. Mixing both for one Demand, reusing an output index, using a bundle for #receipt-complete-v1, or using an unknown evidence policy MUST fail closed.

Late Payee internalization remains required operational behavior. When the Payee returns, it retrieves the stored Delivery, performs the ordinary section 11.3 wallet validation and idempotent internalizeAction, and returns a Receipt. A late Receipt does not revoke, duplicate, or alter the already issued License and MUST NOT create another buyer transaction.

This availability improvement deliberately changes trust and privacy boundaries. The Payee delegates temporary Delivery availability and transaction-acceptance judgment to named providers; the issuer and buyer depend on those providers remaining available; processor acceptance can later be invalidated by conflict or reorganization; the exact destination script and provider relationships become linkable protocol evidence; and key release may occur before wallet internalization or mining. A Payee that does not accept those tradeoffs selects #receipt-complete-v1. A provider outage leaves the one transaction pending; it never permits a weaker proof. Deployments SHOULD separate Payee wallet, Delivery provider, evidence provider, and issuer failure domains, even though a small reference fixture may co-locate roles while preserving distinct identities, endpoints, stores, and signed responsibilities.

11.6 Deterministic-CBOR HTTP binding

The multilateral acquisition endpoint uses POST and deterministic LCH CBOR. The exact request media type is:

application/vnd.bsv.lch+cbor; type=<message-type>

The response uses the same media type with the response message type. Parameters are ASCII case-insensitive as HTTP media types, but a sender SHOULD emit the lowercase form above. The following operations are initially registered:

Request message typeRequest valueSuccessResponse message type and value
license-request-preflightsigned License Request204no body
license-requestsigned License Request200quote, signed Quote
payment-demandsigned Payment Demand200payment-readiness, signed Payment Readiness
payment-authorization-requestsigned Payment Demand200payment-authorization, signed Payment Authorization
payment-deliverysigned Payment Delivery200payment-receipt, signed Payment Receipt
payment-delivery-store{ "authorization": signed-object, "delivery": signed-object }200payment-delivery-ack, signed Delivery Acknowledgement
payment-delivery-retrievalsigned Payment Delivery Retrieval200 or 404payment-delivery-stored, stored-delivery map below when found
transaction-evidence-request{ "authorization": signed-object, "atomicBeef": bstr }200transaction-evidence, signed Transaction Evidence
payment-completionPayment Completion map below200license, signed License
license-recovery{ "requestId": bstr .size 32 }200 or 404license, signed License when found
payment-completion = {
  "request": signed-object,
  "quote": signed-object,
  "atomicBeef": bstr,
  "receipts": [* signed-object],
  ? "authorizedOutputs": [* authorized-output-evidence]
}

stored-delivery = {
  "authorization": signed-object,
  "delivery": signed-object,
  "deliveryAcknowledgement": signed-object
}

Payment Completion MUST contain at least one settlement proof and exactly one profile-valid proof for each Demand in its Quote. An empty receipts array is therefore valid only when every Demand is satisfied by an authorized-output bundle.

The License Request preflight and Quote operations use the Offer payment endpoint. Payment Demand preflight, Payment Authorization, and ordinary Payment Delivery use that Demand's endpoint. Storage, retrieval, and transaction-evidence operations use only the endpoints signed in the Payment Authorization. Payment Completion and License recovery use the Offer payment endpoint. A client MUST dispatch by the signed endpoint on each object; it MUST NOT rewrite all destinations to the issuer origin. An implementation MAY mount all roles at the same URL, but MUST still verify every signed role, provider, and Payee identity independently.

This section initially registers the synchronous HTTP binding. A Payee can place that endpoint in front of an asynchronous inbox or message-box service, provided the externally observable request, response, identity, bounds, idempotency, and recovery behavior remains exactly this binding. A future native asynchronous or message-box binding can be registered by an acquisition profile with its own endpoint syntax, authentication, correlation, acknowledgement, polling or reply, expiry, and replay rules. Until then, an implementation-specific transport adapter is not portable protocol evidence and MUST NOT change or omit the signed Demand, Delivery, or Receipt objects.

Every body MUST be deterministic CBOR and MUST be bounded while streaming. Responses MUST use Cache-Control: no-store. A conforming browser endpoint SHOULD support CORS for the origins it serves. Unsupported media or message types, malformed CBOR, invalid signed objects, expired Quotes, payment failure, and unavailable recovery MUST fail without issuing key material. An error response SHOULD carry deterministic CBOR { "code": tstr } with media type application/vnd.bsv.lch+cbor; type=error; HTTP status does not replace the stable LCH error code.

Exact redelivery is idempotent at both Payment Delivery and Payment Completion. A server MUST durably claim a Demand before calling the receiving wallet, return the stored Receipt for the same transaction fingerprint, and reject another transaction fingerprint. Multi-replica deployments require an atomic shared claim; an in-process map is sufficient only for a single-process reference deployment.

12. Quantity-controlled key release

The segmented profile can encrypt the whole Asset under one key period or many. A quantity-controlled Offer SHOULD use key periods no larger than the smallest separately purchasable range.

The Quote converts the semantic Selection to segmentSelection and lists the exact key periods that will be granted. If a requested range touches any part of a key period, the entire period is disclosed and billable under the Offer's rounding rule. The Quote MUST make this enlargement visible before payment.

For the License's exact segmentSelection—or the complete segment range when the semantic Selection is all and segmentSelection is omitted— keyGrants MUST contain every intersecting key period exactly once and MUST NOT contain any other key period. This rule also applies to a whole-Asset License: omitting a later key period is an incomplete delivery, not a valid partial implementation. Possession of ciphertext or a CHIRP leaf does not imply entitlement to every encrypted segment inside it.

Quantity units can include segments, plaintext bytes, pages, events, milliseconds, tokens, samples, or another profile-defined integer unit. The signed Quote is authoritative where compressed-media indexes, transformations, or nested compositions make local price calculation ambiguous.

13. Composition and C2PA

13.1 Required C2PA provenance

An LCH Asset created through odrl:aggregate, odrl:extract, or odrl:derive MUST carry a C2PA 2.4 reference in asset.provenance and a Composition Record in asset.composition. Performing LCH train alone does not make the trained model or another output a derivative Asset under this rule. When a resulting LCH Asset affirmatively claims training provenance, each explicitly identified training source MUST be recorded as an inputTo ingredient. Version 1 does not define dataset-root, batch, or aggregate-source commitments; an application needing them MUST use a future critical profile rather than expanding one ingredient into an implied source graph.

For each source Asset:

  1. the C2PA Manifest MUST contain a current c2pa.ingredient.v3 assertion;
  2. a visible or audible component uses relationship componentOf and a corresponding c2pa.placed action;
  3. an AI or process input that is not a component uses relationship inputTo where C2PA prescribes it;
  4. audio composition SHOULD also record c2pa.mixed or c2pa.remixed as appropriate;
  5. partial use SHOULD be described with C2PA ingredient assertion metadata and regionOfInterest; and
  6. for an LCH source, the ingredient assertion metadata MUST carry the custom field org.bsv.lch.sourceAsset whose value is the source LCH Asset IRI; informationalURI SHOULD carry the same IRI.

The org.bsv.lch.sourceAsset field is an entity-specific assertion-metadata extension permitted by C2PA; it replaces the older documentID convention, which is not a member of the current v3 ingredient map. If a source lacks a C2PA Manifest, C2PA permits an ingredient assertion without activeManifest. The LCH Asset ID and source media type are still recorded. A derived Asset MUST NOT fabricate an active source manifest.

C2PA validates provenance claims; it does not prove that a license was granted or paid. The Composition Record supplies that binding.

13.2 Composition Record

composition-record-body = {
  "version": 1,
  "c2paManifestDigest": bstr .size 32,
  "ingredients": [1* composition-ingredient],
  ? "critical": [* tstr]
}

composition-ingredient = {
  "sourceAssetId": bstr .size 32,
  "sourceLicenseId": bstr .size 32,
  "c2paIngredient": c2pa-hashed-uri,
  "relationship": "componentOf" / "inputTo",
  "sourceSelection": selection,
  "derivedSelection": selection,
  "mappingProfile": tstr,
  ? "nextPolicy": policy-reference,
  ? "settlementReceiptIds": [* bstr .size 32],
  ? "metadata": { * tstr => any }
}

c2pa-hashed-uri = {
  "url": tstr,
  ? "alg": tstr,
  "hash": bstr
}

Every source License MUST grant the action used to create the derivative and cover sourceSelection. c2paIngredient MUST reproduce the C2PA hashed URI that resolves to the corresponding ingredient assertion in the referenced C2PA Manifest; matching only sourceAssetId is insufficient, including when the same source is placed more than once. alg is omitted only where C2PA unambiguously inherits it from the Claim. c2paManifestDigest MUST equal asset.provenance.digest.

The initial mapping profile is:

https://bsv.brc.dev/apps/0170#whole-placement-v1

Under #whole-placement-v1, derivedSelection MUST be { "type": "all" }. Any nonempty selection of the derivative therefore activates the ingredient's complete normalized sourceSelection. Each repeated placement is represented by a distinct ingredient with a distinct c2paIngredient binding, even when the source Asset and License are the same.

Whole placement is deliberately conservative, not edit-restrictive. A License that grants the applicable modify, extract, or derive action can be used for trimming, repetition, time stretching, reversal, distortion, frame-accurate edits, coordinate transforms, mixing, and other editorial operations without registering another LCH mapping profile. Those operations do not change which permissions were granted. Applications MAY describe them in C2PA actions, ingredient metadata, an edit decision list, or the Composition Record's non-critical metadata; a resolver ignores that descriptive metadata when determining obligations. The complete declared sourceSelection remains active for every nonempty selection of the derivative.

Composition Record metadata still obeys the deterministic CBOR restrictions in section 1.2. An application recording a fractional playback rate or scale therefore uses an exact integer ratio or another integer-unit representation, not a CBOR floating-point value. Version 1 does not standardize the vocabulary of that descriptive edit metadata.

This profile does not claim selective or proportional mapping for those edits. A future mapping profile is needed only when an implementation wants a deterministic rule that maps part of a requested derivative back to part of a source, or computes proportional obligations from such a mapping. It MUST define the source and derived units, normalization, transform, intersection, boundary, and rounding rules. An unknown mapping profile is critical to the ingredient and MUST fail closed. C2PA region, action, timeline, or transform metadata provides provenance context but MUST NOT be substituted for a selective settlement mapping profile.

If a source Agreement contains an odrl:nextPolicy Duty, the exact downstream Policy is carried in nextPolicy and MUST be applied to the derivative. If the obligation was discharged when the derivative was created, the corresponding signed Receipt IDs are carried. If it is triggered by future rendering, distribution, training, or another action, it remains live in the derivative's Offers and Licenses.

13.3 Nested payment resolution

When an action on a derived Selection triggers downstream compensation:

  1. inspect only Composition Record entries whose derivedSelection intersects the requested Selection;
  2. map the intersection to the applicable sourceSelection under the ingredient's mappingProfile;
  3. evaluate each source nextPolicy for the requested downstream action;
  4. recurse through any source Composition Records;
  5. flatten the resulting compensation Duties into signed Payment Demands;
  6. create one transaction with all required outputs; and
  7. deliver that transaction directly to every Payee under section 11.

Resolvers MUST track (Asset ID, Duty uid, Selection) , reject cycles, and support at least 32 nesting levels. They MUST reject rather than truncate a graph exceeding their supported depth. Identical Duties are fulfilled once only where ODRL's shared Duty uid semantics and the policy's aggregation rule say they are identical; matching Payee keys alone is not enough to deduplicate obligations.

This supports, for example, a movie whose selected scene contains a song, whose source License in turn carries obligations for independently licensed stems. The movie Seller can receive one output while the song and stem Payees receive their own outputs in the same transaction and receive the Atomic BEEF directly.

13.4 Export behavior

A raw derivative can be exported only if its Agreement grants the required derive, reproduce, unwrap, and, where applicable, distribute actions and no applicable #retainLch Duty remains.

If #retainLch applies, the exported work MUST remain LCH-wrapped and carry the required Composition Record and downstream Policy. If #presentTerms applies, the receiving workflow MUST present and record acceptance of the referenced terms. These rules are evaluated from the License; LCH does not impose one export policy on all works.

14. Initial acquisition profiles

The following usage profile IRIs define initial interoperable behavior. Each Offer still declares the exact payment, key-delivery, encryption, and enforcement mechanisms it selects.

These profiles standardize portable licensing behavior, not an application data model. Catalogue discovery, channel and social metadata, recommendations, thumbnails, previews, waveforms, DAW timelines, edit decision lists, royalty weighting, and similar application concerns remain in application schemas or separately identified critical profiles. Once interoperable semantics for one of those concerns are stable, a future BRC can register it without changing the v1 Header, License, or whole-placement rules.

14.1 Fixed render

https://bsv.brc.dev/apps/0170#fixed-render-v1

  • Grants one or more of play, display, read, execute, or render.
  • Uses fixed BSV pricing.
  • A full core implementation supports BRC-105, segmented AES-256-GCM, and BRC-78 key delivery.
  • Offline, archive, unwrap, copy, print, and redistribution rights are determined solely by the Agreement.

14.2 Metered range

https://bsv.brc.dev/apps/0170#metered-range-v1

  • Requires a Selection and an exact signed Quote.
  • Uses independently releasable key periods.
  • Prices an integer quantity or returns exact Payment Demands.
  • The License includes only intersecting key periods and exact segment coverage.

14.3 Metered event

https://bsv.brc.dev/apps/0170#metered-event-v1

  • Covers a page, play, open, render, inference, or other counted event.
  • Uses ODRL count, event, dateTime, or related constraints.
  • MAY use BRC-105 or BRC-121.
  • The resulting License records whether the event produced a reusable entitlement, a time-bounded entitlement, or exactly one completed action. A server MUST NOT charge a reread that the existing Agreement already permits.

14.4 Rental

https://bsv.brc.dev/apps/0170#rental-v1

  • Uses an ODRL Agreement with dateTime, elapsedTime, or meteredTime constraints.
  • Explicitly declares connectivity and enforcement class.
  • Offline playback is permitted only when the Agreement says so; online enforcement is not inferred from the word “rental.”

14.5 Composition

https://bsv.brc.dev/apps/0170#compose-v1

  • Grants aggregate, extract, or derive for a Selection.
  • Requires C2PA and a Composition Record.
  • Preserves or fulfills nextPolicy, retainLch, presentTerms, compensation, attribution, reporting, and watermark Duties.
  • Uses multilateral settlement when more than one Payee must be paid for the action.

14.6 AI training

https://bsv.brc.dev/apps/0170#training-v1

  • Grants LCH train for a declared Selection, purpose, model class, or other ODRL constraints.
  • Does not imply display, redistribution, extraction for unrelated use, or ownership of the source.
  • Does not require a Composition Record merely because training occurred. When a resulting LCH Asset explicitly claims training provenance, every individually identified source uses a C2PA inputTo ingredient and an LCH Composition Record; dataset-root and batch commitments await a future profile.
  • Carries any attribution, reporting, deletion, output-policy, compensation, or wrapper Duties in ODRL.

Technical DRM cannot generally prove that plaintext was never used in an undeclared training process. This profile standardizes permission, payment, evidence, and conforming-tool behavior without overstating enforcement.

15. Application and wallet behavior

An application claiming LCH support MUST publish or expose the exact usage profiles, payment mechanisms, encryption mechanisms, key-delivery mechanisms, enforcement classes, ODRL terms, and selector types it implements. A bare claim of “BRC-170 compatible” is insufficient.

Applications MUST pass payment construction through the BRC-100 wallet boundary. They SHOULD label the action with the Asset ID, Offer ID, usage profile, requested action, and a human-readable description suitable for BRC-65 and BRC-111 wallet policy. They MUST NOT infer permission to spend from an LCH Policy; wallet spending authorization is separate from content permission.

A wallet MAY approve repetitive low-value purchases according to its own persisted permissions, counterparty trust, budgets, labels, and transaction details. This BRC neither requires a prompt for every micropayment nor authorizes an application to bypass wallet policy.

16. Reference conformance cases

The following cases are normative as to expected pass/fail behavior; brands, titles, amounts, endpoints, and keys in their data are illustrative.

  1. Purchased MP3. song.mp3.lch offers play for a fixed BRC-105 payment. The License permits play and archive, prohibits unwrap, and permits offline playback. A player decrypts authenticated records and plays them; an unwrapper rejects export.
  2. Web font. font.woff2.lch offers display for a fixed price and raw-key delivery over mutually authenticated HTTPS. A browser integration loads it through FontFace, preserves WOFF/OpenType license metadata, and does not expose a downloadable WOFF2 because unwrap and distribute are absent.
  3. Pay-per-page publication. A document has free page zero and a metered-event-v1 Offer for other pages. Buying page four returns an Agreement permitting read for that page for 30 days. Reopening page four within that interval does not pay again.
  4. Range audio acquisition. A long recording uses four key periods. A request for segments [2,4) returns keys only for intersecting periods. Those records authenticate; an attempt to decrypt another period has no granted key and fails closed.
  5. DAW composition. A loop License grants derive for a selected interval and requires a downstream Policy. A song repeats the loop, reverses one placement, time-stretches another, and distorts a third. Every placement has a distinct C2PA v3 componentOf ingredient; the edit descriptions are non-critical provenance metadata; every ingredient still uses whole-placement-v1; and the Composition Record carries the required nextPolicy. The edits neither expand the License nor require a selective mapping profile.
  6. Nested movie settlement. A requested movie scene intersects a song ingredient, which intersects licensed stem ingredients. The resolver detects no cycle, produces all required Payment Demands, creates one transaction with all outputs, directly delivers the Atomic BEEF to each Payee, obtains every Receipt, and receives the movie License.
  7. Federated band settlement. The downstream-work issuer, drummer Payee, and composer Payee operate three distinct HTTPS origins and independently controlled wallets. The client persists one funded transaction, delivers only to the endpoint signed in each Demand, retains the drummer Receipt while the composer endpoint is unavailable, and later retries the same composer Delivery. Sending either Demand to the other Payee endpoint is rejected, no replacement transaction is created, and issuer completion succeeds only with both Receipts.
  8. Offline authorized Payee. A drummer selects authorized-output-v1, signs exact BRC-29 output and provider details, and then goes offline after renewed signed readiness. The buyer creates one transaction, the exact output is accepted by the authorized processor, the signed Delivery is retained through recovery, and the issuer releases the License from the complete evidence bundle. When the drummer returns, authenticated retrieval internalizes that same output once and returns a late Receipt; no second transaction or License is created.
  9. Unavailable or invalid fallback. The same flow remains pending when the Delivery provider is unavailable, its retention ends before recoveryUntil, the transaction evidence is only broadcast, the provider identity or policy differs, the output script or amount differs, or another transaction was already accepted for the Authorization. None of those cases releases keys. A receipt-complete Demand whose Payee goes offline also remains pending because silence does not select the fallback profile.
  10. AI training. A dataset Offer grants train for a stated purpose but not display, unwrap, or distribute. A conforming trainer records inputTo provenance where required and rejects an attempted raw export.
  11. Rental. A License permits play until a fixed time and allows 24 hours offline. Playback works offline inside that interval and fails after it. A later status change does not claim to erase a raw CEK previously delivered.
  12. Unknown semantics. A client that understands the Header but not a critical policy term, settlement profile, evidence policy, or mechanism rejects that acquisition profile and may select another fully supported profile.
  13. Tampering. Modified Header CBOR, wrong ciphertext digest, wrong CEK, reordered records, modified AAD fields, reused payment demands or Authorizations, missing settlement proofs, C2PA ingredient mismatch, authority cycles, and composition cycles are all rejected.

17. Conformance vectors

The companion vector set is apps/media/0170-conformance-vectors.json. Its C2PA composition pair is 0170-c2pa-composition.mp3 plus 0170-c2pa-composition.c2pa. The vector set contains deterministic diagnostic objects and expected:

  • deterministic CBOR bytes and object IDs;
  • LCH container bytes and detached-header equivalence;
  • segmented AES-256-GCM records, Key IDs, ciphertext digest, range offsets, successful partial decryption, and tamper failures;
  • Offer and Agreement Policy digests;
  • BRC-77 object signatures and BRC-78 CEK recovery;
  • normalized selections and unit prices;
  • BRC-29-derived multi-payee locking scripts from both sender and receiving-wallet forSelf derivation, output indices, Demand IDs, signed Delivery IDs, and Receipt IDs;
  • receipt-complete and authorized-output Demand selection, Payee-side exact destination authorization, buyer-side script comparison, signed processor acceptance, durable Delivery acknowledgement, authenticated late retrieval, and mixed-profile completion;
  • offline Payee success plus wrong script, wrong amount, wrong provider, broadcast-only evidence, insufficient retention, unavailable provider, repeated proof, conflicting accepted transaction, and strict-profile fallback rejection;
  • deterministic-CBOR HTTP request payloads, Payment Completion, recovery, exact media types, success statuses, and stable error envelopes;
  • finalized randomized-output matching plus missing, duplicate, and ambiguous output rejection;
  • Quote, Demand, and BRC-105 recovery deadlines and idempotent redelivery;
  • fresh unspent, stale, mempool-spent, confirmed-spent, unknown, and reorganization-affected Authority revocation states;
  • C2PA ingredient-to-Composition-Record bindings;
  • whole-placement mapping, distinct repeated ingredients, reversal, rational-rate time warps, distortion metadata, unsupported selective-mapping rejection, nested-obligation flattening, and cycle rejection;
  • inclusive notBefore plus exclusive notAfter, expiresAt, and recoveryUntil boundaries;
  • complete whole-Asset key-period delivery plus missing, duplicate, and out-of-selection Key ID rejection; and
  • the pass/fail outcomes for every reference case in section 16.

A conforming implementation MUST reproduce the success vectors it claims to support and MUST reject the corresponding negative vectors. Cryptographic values in the vector set use disclosed private keys and MUST never be reused outside testing.

The C2PA pair is signed with c2patool's disclosed development certificate. C2PA claim-signature, hashed-URI, assertion, and asset-binding validation MUST succeed; signingCredential.untrusted is the expected trust result for that test certificate and MUST NOT be treated as a production trust assertion.

18. Error handling

Implementations SHOULD expose stable errors at least as specific as:

CodeMeaning
ERR_LCH_FRAMINGMagic, length, trailing payload, or version invalid
ERR_LCH_CBORCBOR is not well formed or not deterministic LCH CBOR
ERR_LCH_SIGNATURERequired BRC-77 signature invalid
ERR_LCH_AUTHORITYSeller, issuer, releaser, publisher, or Payee authority invalid
ERR_LCH_REVOCATIONAuthority revocation status is spent, stale, unknown, or invalidated by reorganization
ERR_LCH_ENDPOINTEndpoint or locator failed URL, address, redirect, origin, or identity validation
ERR_LCH_PROFILE_UNSUPPORTEDAcquisition profile or critical mechanism unsupported
ERR_LCH_POLICYODRL invalid, conflicting, unsupported, or does not grant the action
ERR_LCH_TERMSPolicy or human terms digest mismatch
ERR_LCH_CONTENT_UNAVAILABLENo required ciphertext source or range is currently available
ERR_LCH_CONTENT_DIGESTCiphertext does not match the Asset Body
ERR_LCH_KEYKey delivery invalid or CEK does not match Key ID
ERR_LCH_AUTHENTICATIONAn encrypted record tag failed
ERR_LCH_SELECTIONSelection invalid or outside the Asset
ERR_LCH_QUOTEQuote expired, mismatched, or arithmetically invalid
ERR_LCH_PAYMENTPayment missing, invalid, replayed, or underfunded
ERR_LCH_DELIVERYDirect Payee delivery, durable storage, or authenticated retrieval failed
ERR_LCH_LICENSELicense invalid, expired, revoked under its mechanism, or mismatched
ERR_LCH_PROVENANCERequired C2PA or Composition Record validation failed
ERR_LCH_CYCLEAuthority or composition graph contains a cycle

Errors MUST NOT include CEKs, decrypted content, private keys, BRC-78 plaintexts, or unrelated wallet data.

19. Security and privacy considerations

Untrusted parsers

Headers, ODRL Policies, C2PA manifests, media metadata, decrypted files, and DRM messages are untrusted input. Implementations MUST impose defensible depth, allocation, string, array, header-size, policy-size, and media-decoder limits. The framing length MUST be checked before allocation. URLs MUST be subject to scheme, redirect, local-network, and origin policy to prevent SSRF and credential leakage.

Nonce and key reuse

AES-GCM confidentiality and authenticity fail catastrophically when a key/IV pair repeats. Publishers MUST generate fresh CEKs and nonce prefixes exactly as section 8 requires. A conforming publisher SHOULD maintain a local duplicate detector for encryption IDs and Key IDs in addition to using a cryptographically secure generator.

Record substitution

The AAD binds each record to its encryption ID, position, total segment count, plaintext length, and Key ID. Applications MUST supply the exact AAD and MUST NOT decrypt records as standalone AES-GCM messages with empty associated data.

Plaintext and metadata disclosure

Ciphertext length, media type, filename, Seller, rights holders, prices, Payees, and acquisition requests can reveal sensitive information. A plaintext digest additionally reveals equality with a known file. Publishers can omit that digest, use generic public metadata, pad within a separately specified encryption mechanism, or choose privacy-preserving transports. Those choices can reduce discoverability and preview quality.

Multilateral transactions expose that the outputs were paid together. Direct delivery exposes the buyer and request to every Payee under the authenticated profile. Authorized-output settlement additionally discloses the exact destination script and links the Payee, buyer, evidence provider, Delivery provider, and issuer completion record. Providers MUST restrict unrelated access to stored Deliveries and minimize operational logs while retaining the audit evidence their policy promises. Privacy-enhancing future profiles must state what linkages they remove and must not weaken payment verification silently.

DRM limits

Any application capable of rendering plaintext can be modified, instrumented, recorded, or subjected to the analog hole unless a stronger protected path changes the threat model. #conformingApplication describes interoperable behavior, not impossibility of circumvention. Watermarks can aid attribution but are not access control.

Seller and issuer failure

Cryptography proves that bytes, policies, signatures, keys, and payments match their commitments. It cannot prove that content is worthwhile, that descriptive claims are true, or that an issuer will behave honestly after receiving payment. Identity, authority, payment receipts, idempotent recovery, and reproducible failure evidence make disputes more attributable; they do not remove counterparty risk.

Offline use and revocation

Once a buyer possesses a raw CEK or plaintext, revocation cannot make it unknown. A policy promising both permanent offline access and retroactive technical revocation is contradictory and invalid. Protected-module and online profiles can provide different behavior only within their declared boundaries.

Composition disclosure and graph attacks

C2PA and LCH Composition Records can reveal creative inputs, license relationships, and commercial splits. Implementations must obtain the permissions required to publish that information. Recursive resolvers MUST detect cycles, cap resource use, verify every source independently, and reject missing rather than silently ignored obligations.

Payment recovery

An ambiguous network failure after transaction creation is not evidence that payment failed. Clients retain the existing Atomic BEEF and retry direct delivery and license recovery. They do not automatically create a second transaction.

Authorized-output fallback moves rather than removes availability and finality risk. The Payee explicitly trusts named providers before payment; an unavailable provider leaves settlement pending, and processor acceptance can later be displaced by a conflict or reorganization. Implementations MUST preserve the evidenced lifecycle label, MUST NOT describe accepted evidence as mined, and SHOULD expose these provider dependencies before the Payee enables the profile.

LCH provides canonical bytes, named parties, signed Offers, accepted term digests, buyer-specific Agreements, authority chains, payment transactions, direct Payee receipts, timestamps, and provenance. Those records can improve reproducibility and evidence in a dispute.

LCH standardizes protocol records and conformance behavior; it does not define copyright ownership, contract formation, consumer rights, exhaustion, fair use or fair dealing, privacy obligations, choice of law, tax, securities treatment, or the applicability of anti-circumvention rules. A cryptographic claim of authority can be false in the real world. Human-readable terms and applicable rules remain controlling where machine policy is incomplete or ineffective.

Applications MUST NOT describe an LCH signature as a government-qualified signature, a C2PA claim as proof of copyright ownership, or a DRM mechanism as universal legal enforcement unless an independent legal basis supports that statement.

21. Implementation guidance

A practical implementation can be layered:

  1. deterministic CBOR and .lch framing;
  2. Asset ID and BRC-77 verification;
  3. ODRL validation with the pinned LCH Profile;
  4. segmented AES-256-GCM range reads;
  5. BRC-105 purchase and BRC-78 key delivery;
  6. portable License storage and recovery;
  7. metered selections and key periods;
  8. Authority Grants;
  9. multilateral direct settlement;
  10. Payee-authorized output settlement with durable retrieval; and
  11. C2PA composition and nested downstream policies.

An end-to-end reference deployment has these visible role classes: a creator wizard that produces the protected Asset and Offer; a content host implementing the ContentSink/ContentSource boundary; an issuer endpoint implementing section 11.6; one independently routable delivery service and receiving BRC-100 wallet for every Payee; optional Payee-authorized transaction-evidence and durable-Delivery providers; and a player that separates non-spending preflight from the buyer wallet's createAction. The roles need not share an origin, process, operator, or wallet . Under receipt-complete settlement, Payee wallets directly receive and acknowledge Demand outputs through internalizeAction. Under authorized-output settlement, the Payee signs its exact destination and provider choices before payment, and later retrieves the signed Delivery for the same wallet operation. The issuer persists immutable Quotes, Demands, settlement proofs, issued Licenses, and protected CEKs needed for recovery; the buyer persists its funded fan-out state until completion or recoveryUntil.

A single-process reference server MAY combine those roles with in-memory stores while still exposing distinct endpoints and signed identities. A horizontally scaled or value-bearing service needs a transactional shared Payment Demand and Authorization ledger, durable Delivery retention through its signed deadline, atomic transaction-evidence claims, durable License recovery, encrypted CEK storage, independently controlled wallet identities, authenticated creator publication, bounded public endpoints, and CHIRP, UHRP, or HTTPS ciphertext retention. Those operational substitutions do not change the signed LCH objects.

The minimum full core Reader implements fixed-render-v1 with deterministic CBOR, BRC-77, ODRL, BRC-105, BRC-78, and segmented AES-256-GCM. Smaller applications may truthfully claim a narrower profile and mechanism set.

References

Was this helpful?

Search Beersy

Search standards by number, title, author or topic