Skip to content

Add BRC-369: Keyed Content and Conditional Key Release - #233

Merged
sirdeggen merged 1 commit into
bsv-blockchain:masterfrom
vincemedia:brc-369-keyed-content
Aug 28, 2026
Merged

Add BRC-369: Keyed Content and Conditional Key Release#233
sirdeggen merged 1 commit into
bsv-blockchain:masterfrom
vincemedia:brc-369-keyed-content

Conversation

@vincemedia

Copy link
Copy Markdown
Contributor

Summary

Encrypt content once, publish the ciphertext where anybody can fetch it, and release the decryption key only to parties who satisfy a stated condition. Two condition profiles are given: a payment, and a BRC-190 access-gate verdict.

This closes a hole the Access Gates document names in its own section 9: "a room whose confidentiality matters must key its contents so that non-holders cannot decrypt them; that mechanism is out of scope here."

Depends on #232, which restores apps/0190.md. Section 8 and the References entry link to that path, so this should merge after it.

What it rests on, and what it adds

Almost all of it is assembled from primitives already here: BRC-42/43 derivation, the BRC-2 symmetric construction, the BRC-78 serialization, BRC-33 transport, BRC-26 content addressing, BRC-29 payments, BRC-94 proofs. The encrypt-once-release-per-recipient pattern is BRC-52's keyring, used unchanged and credited as such in Prior Art and in section 5.2.

What it adds is a commitment to the content key, published and signed before any recipient exists. BRC-94 already settles, from public values alone, that a revealed secret was computed correctly. Publishing an object raises a second and independent question that does not arise in BRC-69's audit setting: is this the key for that object? A correctly computed secret can be the wrong scalar and the right scalar can be wrapped badly, so neither answer implies the other. The commitment settles the second, and section 5.3 is the first release path here where a recipient can settle both.

Points a reviewer may want to go at first

  • Section 2.2 defaults to a digest commitment rather than k * G. A point commitment published durably reduces the content's confidentiality to the discrete logarithm problem rather than AES-256, retroactively and permanently. The point form is kept only for section 6.4 splitting, which needs the algebraic structure.
  • Section 5.2 declines BRC-78's protocol ID and random key ID, taking keyed content release and a key ID derived from the content id and epoch, on the same reasoning BRC-52 used for its keyrings: permissions are granted per protocol under BRC-43/BRC-100, and a derived key ID binds the wrapper to what it carries.
  • "Why a Keyed Room Must Rotate" is a negative result stated separately because it reaches past this document: keying group content without rekeying on membership change leaves a room strictly worse off than the rendering convention it replaced, and the failure is silent.
  • Section 7.2 requires payees to be declared and the payer's client to verify them before sending, and requires the author to be shown their net rather than the headline price.
  • Section 9 and the two ledgers state plainly what is not achievable: any recipient can republish, leaks are unattributable without pairings, and the releaser's authority is verifiable while its behaviour is not.

Conformance

Documentation only. Vectors live outside this repository per the request on #224 and are linked from the Implementations section: vincemedia/brc-conformance under brc-369/, 56 checks, Python standard library only, no network. They include the substituted-key case of section 5.4, where the hash and commitment checks pass and the authentication tag fails.

Authorship

Ty Everett and Deggen are listed as co-authors because the substrate is theirs. Neither has reviewed this document, and if either would rather not be listed, or would rather be acknowledged than credited as an author, say so and I will send a follow-up immediately. The same applies to Brayden Langley for BRC-52, whose keyring pattern section 5.2 reuses directly.

🤖 Generated with Claude Code

Encrypt content once, publish the ciphertext openly, and release the
decryption key only to parties satisfying a stated condition. Two
condition profiles: a payment, and a BRC-190 access-gate verdict.

The mechanism rests on primitives this repository already specifies:
BRC-42/43 derivation, the BRC-2 symmetric construction, the BRC-78
serialization, BRC-33 transport, BRC-26 content addressing, BRC-29
payments and BRC-94 proofs. The encrypt-once-release-per-recipient
pattern is BRC-52's keyring, used unchanged.

What it adds is a commitment to the content key, published and signed
before any recipient exists, so a recipient can establish that the key
they were handed is the key for the object rather than trusting that it
is. BRC-94 already settles that a revealed secret was computed
correctly; the commitment settles the separate question of whether the
correctly computed secret is the right one, which only arises once there
is a published object to commit against.

Depends on bsv-blockchain#232, which restores apps/0190.md. Section 8 and the
References entry link to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 23, 2026 16:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the new documentation standard BRC-369: Keyed Content and Conditional Key Release, and wires it into the repository’s indexes/TOCs so it appears in navigation alongside existing BRCs.

Changes:

  • Add new standard document peer-to-peer/0369.md describing keyed content encryption and conditional key release flows.
  • Add BRC-369 to the top-level BRC index (README.md) and the peer-to-peer index (peer-to-peer/README.md).
  • Add BRC-369 to the mdBook summary (SUMMARY.md) for navigation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
SUMMARY.md Adds the BRC-369 entry to the mdBook ToC (currently placed under Payments).
README.md Adds BRC-369 to the global BRC index table.
peer-to-peer/README.md Adds BRC-369 to the peer-to-peer directory index table.
peer-to-peer/0369.md Introduces the full BRC-369 specification text.
Suppressed comments (6)

peer-to-peer/0369.md:217

  • The descriptor field table marks content.locator as MUST, but section 3.1 states a descriptor must carry at least one of content.locator and content.inline. Please align the table’s requirement with the normative text so implementers don’t get conflicting MUST/conditional guidance.
| `content.locator`     | MUST        | Array of sources. MAY be empty where the ciphertext is inline                                                                                                           |
| `content.salt`        | MUST        | Four bytes, hex, per section 2.3                                                                                                                                        |
| `content.segment`     | MUST        | Segment size in bytes                                                                                                                                                   |
| `content.inline`      | conditional | Base64 ciphertext, where no locator is given                                                                                                                            |

peer-to-peer/0369.md:25

  • This link points to ../apps/0190.md, but apps/0190.md is not present in this branch (only apps/0146.md exists), so the reference is currently broken.
[BRC-190](../apps/0190.md) section 9 says what an access gate is not:

peer-to-peer/0369.md:53

  • This link points to ../apps/0190.md, but apps/0190.md is not present in this branch (only apps/0146.md exists), so the reference is currently broken.
**Consumer paywalls.** Substack, Patreon and Medium are stored grants with a server attached: a subscription row is written, and every read consults it. [BRC-190](../apps/0190.md)'s Prior Art sets out what a stored grant costs, and the whole of it transfers, with one addition specific to reading rather than joining. When the platform ends, the row ends, and so does access to everything bought under it. A recipient here holds a key against content addressed by hash, so what they bought outlives the arrangement that sold it. That is the property being bought, and it is the only one worth the additional machinery.

peer-to-peer/0369.md:461

  • This link points to ../apps/0190.md, but apps/0190.md is not present in this branch (only apps/0146.md exists), so the reference is currently broken.
[BRC-190](../apps/0190.md) owns the gate. Its section 3.3 verdict is the input to the gate profile of section 8 here, and its section 2.1 `keyed` field is where a room states that it uses this document. Nothing here evaluates a gate condition, defines one, or adds one. Section 5 of that document is a **fee** and is not a keyed release: a fee is periodic, denominated in the gate's asset, paid to a named recipient and enforced by the gate itself, so a reader who stops paying stops qualifying. A release under this document is once per epoch and enforced by the key, so a recipient who has been given one keeps what it opens whatever the room later decides.

peer-to-peer/0369.md:477

  • This link points to ../apps/0190.md, but apps/0190.md is not present in this branch (only apps/0146.md exists), so the reference is currently broken.
[BRC-190](../apps/0190.md) section 6 already accepts that lapsing is not retroactive: a participant who received messages has them, and no client can change that. What rotation preserves is the other half, that lapsing is at least **prospective**. Section 8 of this document turns that into a MUST, section 8.2 fixes when, and section 8.4 states what rotation does not recover.

peer-to-peer/0369.md:845

  • This reference list entry links to ../apps/0190.md, but apps/0190.md is not present in this branch (only apps/0146.md exists), so the reference is currently broken.
- [BRC-190: Access Gates for Metanet Rooms](../apps/0190.md)

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread peer-to-peer/0369.md
}
```

`request` is the content id of section 4.2.3. `evidence` carries what the condition requires and is empty for the gate condition, where the releaser evaluates public facts about the sender rather than reading anything the sender supplies. A releaser MUST reject a request naming a content id it does not serve, rather than releasing a key for a descriptor it has not read. 2. The envelope signature identifies the recipient. A releaser MUST resolve and verify the sender per BRC-169 section 5.7 before evaluating any condition that depends on who is asking. 3. A releaser MUST evaluate the condition itself. It MUST NOT accept a recipient's assertion that the condition is met. 4. A releaser is a service anybody can address, and evaluating a condition costs it work before it has been paid anything. A releaser MAY therefore set a toll on its messagebox under BRC-169 section 8.2, which the requesting client surfaces and attaches like any other. The toll is a separate amount from the price and MUST be shown separately at confirmation, per BRC-218 section 5.1.4. A releaser SHOULD NOT set one where it is also a payee, since it is then charging twice for one transaction.
Comment thread peer-to-peer/0369.md
Comment on lines +151 to +152
A descriptor MUST carry at least one of `content.locator` and `content.inline`. Where both are present they MUST be the same bytes, and a recipient that finds otherwise MUST treat the descriptor as malformed rather than preferring one: two sources disagreeing under one hash means at least one is lying, and guessing which is how a client ships a substitution attack.
3. A descriptor MAY list several locators for one hash. They are alternative sources for identical bytes, not alternative content.
Comment thread peer-to-peer/0369.md

That is what makes this a verification rather than a trust relationship. [BRC-94](../key-derivation/0094.md) already settles, from public values alone, that a revealed secret was computed correctly, and this document uses it as written. The commitment settles the separate question of whether the correctly computed secret was the key for this object, which only arises once there is a published object to commit against. The primitives are borrowed and the Prior Art section says from where.

Two condition profiles are given: a payment, and an access-gate verdict under [BRC-190](../apps/0190.md). The first is what a paid post needs. The second is what a room with something to hide needs, and it carries a rotation requirement the first does not.
Comment thread SUMMARY.md
Comment on lines 152 to 156
* [Simple 402 Payments](./payments/0121.md)
* [PeerPay URI Scheme for BRC-29 Payments](./payments/0125.md)
* [Unlinkable Payments under the Identity Paradigm](./payments/0228.md)
* [Keyed Content and Conditional Key Release](./peer-to-peer/0369.md)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants