Add BRC-369: Keyed Content and Conditional Key Release - #233
Merged
sirdeggen merged 1 commit intoAug 28, 2026
Conversation
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>
Contributor
There was a problem hiding this comment.
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.mddescribing 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.locatoras MUST, but section 3.1 states a descriptor must carry at least one ofcontent.locatorandcontent.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, butapps/0190.mdis not present in this branch (onlyapps/0146.mdexists), 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, butapps/0190.mdis not present in this branch (onlyapps/0146.mdexists), 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, butapps/0190.mdis not present in this branch (onlyapps/0146.mdexists), 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, butapps/0190.mdis not present in this branch (onlyapps/0146.mdexists), 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, butapps/0190.mdis not present in this branch (onlyapps/0146.mdexists), 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.
| } | ||
| ``` | ||
|
|
||
| `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 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. |
|
|
||
| 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 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) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
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.keyed content releaseand 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.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