BRC-370 Tokens

Sealed 1Sat Ordinal Reveal

This BRC specifies how the content of a 1Sat Ordinal is sealed as keyed content (BRC-369) inscribed on chain and later revealed, either to everyone or to one chosen recipient, without re-inscribing. A sealing party encrypts the content under a fresh BRC-369 content key and inscribes the ciphertext in the ordinary inscription envelope; the plaintext is never

RexStarBSV (RexStarBSV@protonmail.com)

How it connects

Relationships

Authoritative content mirror

Full upstream text

View source ↗
Rendered from tokens/0370.md at the indexed upstream commit

Abstract

This BRC specifies how the content of a 1Sat Ordinal is sealed as keyed content (BRC-369) inscribed on chain and later revealed, either to everyone or to one chosen recipient, without re-inscribing. A sealing party encrypts the content under a fresh BRC-369 content key and inscribes the ciphertext in the ordinary inscription envelope; the plaintext is never on chain. This BRC reuses BRC-369's content key, its key commitment, and its local verification unchanged, and supplies what BRC-369 leaves open: an on-chain carrier (the ordinal's own envelope rather than off-chain storage addressed by hash), a binding of the key to one ordinal by the hash of its inscription output script, and a public-reveal mode. Two reveal mechanisms are defined over that one sealed ordinal. The first is a public reveal, which BRC-369 does not define: an unspendable data output, under a dedicated tag, that publishes the content key together with the script-id binding and that ordinal's genesis outpoint, so that any holder of the ciphertext confirms the key against the commitment and decrypts with no trusted indexer. The second is a targeted reveal: an off-chain, owner-signed grant that wraps the same key to a single recipient's identity key with a fully specified public-key encryption scheme, the role BRC-369 gives its per-recipient release, so that only that recipient decrypts while the world still sees only ciphertext. The sealed field carries BRC-369's commitment to the content key, and the grant signs that commitment and names its recipient, so one sealed ordinal has exactly one revealable content and one owner-chosen recipient per grant. Both reveals are irreversible once delivered, and both are kept out of any unrelated on-chain record feed by a reserved tag of their own. This document fixes the on-chain sealing format, the public-reveal output to the byte, the targeted-reveal grant and its signed range, the key wrap to the byte, the key-to-ordinal binding, and the verification each party performs, reusing BRC-369 for the content key and its commitment.

Motivation

An inscription envelope places content in a transaction output so that anyone can read it. For a record whose value depends on controlled disclosure, a collectible meant to be unveiled, a licensed work, a credential, an evidentiary document, or any artifact that must stay private until a chosen moment or a chosen reader, plaintext on chain is the wrong default: chain data is permanent and world-readable the instant it confirms. The owner wants to publish the artifact once, permanently, as ciphertext, and keep the single decision of who can read it and when.

Sealing the content under a random key solves the storage half: the ciphertext can live on chain forever and reveals nothing. The reveal half is where interoperation breaks, and it breaks in four ways that this BRC closes.

  1. Binding and location. A published key is useless, and a wrongly matched key is dangerous, unless a reader can tell which sealed ordinal a given key opens and where to read that ordinal's ciphertext. The key must be bound to one ordinal by a value both the publisher and every reader compute independently from the ordinal itself, and the reveal must name the on-chain location of the ciphertext, so that no lookup service is trusted for either.

  2. One content, one key. Authenticated encryption alone does not stop a sealer who controls the ciphertext and the keys from crafting one on-chain field that opens to two different plaintexts under two different keys. A sealed ordinal commits, at seal time, to the single key that opens it, so a public reveal and a targeted grant cannot disclose two different "truths" for the same ordinal. This BRC does not re-derive that commitment; it reuses BRC-369's content-key commitment, which already solves exactly this, and applies it on chain.

  3. Two postures, one artifact. Public disclosure (everyone may read) and targeted disclosure (one named party may read) are different trust models, but they must apply to the same sealed ordinal without re-inscribing it. One is an on-chain publication of the key; the other is an off-chain delivery of the key wrapped to a recipient, bound to that recipient so a holder of the key cannot re-aim the owner's signed grant at someone else.

  4. Feed isolation. A key-reveal output is an OP_RETURN data output, the same shape many unrelated protocols use. A reveal for a sealed ordinal must not be ingested, counted, or mistaken for a record in any other protocol's feed. It must carry a tag of its own and nothing that collides with another tag.

This BRC specifies the sealing, the commitment, the two reveals, the wrap, and the binding so that a sealing party, a public reader, and a targeted recipient, none of whom has spoken to the others, agree on what opens what.

Scope and conformance

Section 1 defines terms. Section 2 specifies the sealed ordinal: the BRC-369 content key and commitment, the symmetric sealing, and the ciphertext's placement in the envelope. Section 3 specifies the public reveal output to the byte and the key-to-ordinal binding. Section 4 specifies the targeted reveal grant: its fields, its signed range, and the key wrap to the byte. Section 5 specifies verification for a public reader and for a targeted recipient. Section 6 lists every requirement by role. The requirement words MUST, MUST NOT, REQUIRED, SHOULD, and MAY are to be read as in RFC 2119.

A conforming sealing party produces a sealed ordinal per section 2 and, when it reveals, a public reveal per section 3 or a targeted reveal per section 4. A conforming reader or recipient accepts a reveal only when the checks of section 5 pass.

Relationship to existing standards

Keyed content

The content key, its commitment, and the local verification are BRC-369 (Keyed Content and Conditional Key Release), reused unchanged. BRC-369 fixes how a publisher commits to a content key before any recipient exists and how a party handed a candidate key checks it locally, in a fixed order, against the commitment and the authentication tag; that primitive is what makes a reveal checkable without a trusted party, and this BRC does not restate it. What this BRC adds is the carrier and the postures BRC-369 leaves open: the ciphertext is inscribed on chain in the ordinal's own envelope rather than held off chain and addressed by a descriptor hash, the content key is bound to one ordinal by script_id (section 1), and a public-reveal mode (section 3) publishes the key to everyone, which BRC-369 deliberately does not offer. The sealed field of section 2 is a BRC-369 content key and digest commitment in an on-chain single-blob framing, in place of BRC-369's segmented, off-chain, descriptor-addressed one.

Inscription envelopes and the single satoshi

The sealed content rides in the inscription envelope on a single-satoshi output, as defined by the 1Sat Ordinals inscription-envelope format (BRC-160) and the single-satoshi token and origin-tracking conventions (BRC-159). This BRC does not change the envelope; the envelope's content is ciphertext rather than plaintext, which the envelope format already permits since its content is an opaque byte string. The ordinal's genesis output, the first output that inscribed the sealed content, is its origin in the sense of BRC-159.

Data-carrying output scripts

The public reveal of section 3 is a data-carrying output using OP_FALSE OP_RETURN (BRC-18) with a dedicated protocol tag as its first pushed field, in the manner of tagged OP_RETURN protocols. It is deliberately unspendable: it carries no value, only the reveal payload.

Message signatures

The grant of section 4 is signed by the owner's identity key with a plain ECDSA signature over secp256k1, domain-separated and over a canonical encoding fixed in 4.3. This is a direct signature by the identity key itself, publicly verifiable against that key; it is not a key-derived signature in the sense of BRC-3 / BRC-42 / BRC-43, and this BRC does not rely on those schemes for it. Section 4.3 fixes the domain separation, the canonical encoding, and the signed range.

Key wrap

The targeted wrap of section 4.4 plays the role of BRC-369's per-recipient key release (BRC-369 section 5.2, itself the keyring operation of BRC-52): it delivers the content key to one recipient and no other. BRC-369 performs that release through a releaser's messagebox, using the non-ephemeral BRC-78 serialization and BRC-42/43 derivation, which suits a service that holds a persistent identity and evaluates a condition. A sealed-ordinal grant has no releaser and no condition: the owner hands the key to the recipient directly, often offline as a file or a QR, where an ephemeral-sender scheme fits better because the recipient needs only its own key and the ephemeral public key in the blob. This BRC therefore pins the widely-deployed "BIE1" ECIES to the byte in section 4.4 for the wrap and does not use BRC-369's releaser release.

Authenticated inscriptions

A 1Sat inscription MAY carry an author-identity signature over its output, as BRC-217 (Authenticated 1Sat Inscription) specifies. Section 4.5 states the one constraint sealing places on authorship: an author section MUST NOT be attached to a sealed ordinal, because it would publish the owner's identity in cleartext beside content the owner chose to keep private.

Related disclosure and content protocols

Two existing specifications also seal content and later release a key, and this BRC is neither. BRC-170 (Locked Content Header) is a licensing container for encrypted content whose ciphertext is held off chain and whose key is delivered against a micropayment license; this BRC instead inscribes the ciphertext on chain inside the ordinal's own envelope, binds the key to the ordinal by script_id, and reveals it by the owner's deliberate public or targeted act with no payment layer. BRC-216 (Dead-Man Timed Reveal of a Sealed Secret) discloses an arbitrary secret when a timed or dead-man condition fires; this BRC discloses a 1Sat ordinal's own content at the owner's choosing, and section 3.5 keeps its reveal tag disjoint from any such timed-reveal feed.

Specification

1. Terminology

  • Sealed ordinal: a 1Sat Ordinal whose inscription content is the sealed field of section 2.
  • Reveal key: the BRC-369 content key k, a 32-byte scalar in [1, n-1] on secp256k1 (n the group order), which opens a sealed ordinal's content. It is not the AES key; the AES key is derived from it (section 2.2).
  • Symmetric key: SHA-256("metanet keyed content symmetric v1" || k), the AES-256-GCM key that encrypts the content, per BRC-369 section 2.1.3.
  • Key commitment: SHA-256("metanet keyed content commitment v1" || k), 32 bytes, BRC-369's digest-form commitment (section 2.2). It fixes, at seal time, the single key that opens the sealed ordinal, and its domain differs from the symmetric key's so publishing it reveals neither k nor the symmetric key.
  • Inscription output script: the complete scriptPubKey bytes of the output that first inscribed the sealed content (the genesis output of the ordinal, its origin per BRC-159).
  • Script id: SHA-256(inscription output script), 32 bytes. It binds a reveal to one sealed ordinal.
  • Genesis outpoint: the "<txid>:<vout>" of the genesis output, where txid is the transaction id as 64 lowercase hex characters in display (big-endian) byte order and vout is a decimal integer with no leading zeros. The canonical form matches ^[0-9a-f]{64}:(0|[1-9][0-9]{0,9})$.
  • Public reveal: the on-chain output of section 3 that publishes a reveal key.
  • Targeted reveal grant: the off-chain owner-signed object of section 4 that delivers a reveal key to one recipient.
  • Owner: the party that sealed the ordinal and holds the reveal key.
  • Recipient: the party a targeted reveal grant is addressed to.

2. The sealed ordinal

2.1. The owner MUST generate the reveal key as the BRC-369 content key k (BRC-369 section 2.1): 32 bytes encoding a scalar in [1, n-1] on secp256k1, from a cryptographically secure random source, fresh per sealed ordinal, and not derived from the owner's identity key, from the content, or from any other reusable secret. Reusing a content key across two ordinals is a MUST NOT.

2.2. The sealed field is

nonce || gcm_ciphertext || tag || key_commitment

where nonce is a 12-byte AES-256-GCM nonce chosen freshly at seal time, gcm_ciphertext is the AES-256-GCM encryption of the content with no associated data under the symmetric key SHA-256("metanet keyed content symmetric v1" || k) (BRC-369 section 2.1.3; the symmetric key is derived from k and is never k itself, per BRC-369 section 2.1.4), tag is the 16-byte GCM authentication tag, and key_commitment is SHA-256("metanet keyed content commitment v1" || k) (32 bytes), BRC-369's digest-form commitment (section 2.2). The two domain strings differ (BRC-369 section 2.2.3), so the commitment, appended in the clear, discloses neither k nor the symmetric key. The field is exactly 60 bytes longer than the content. Unlike BRC-369 section 2.3, a sealed ordinal is not segmented: it carries one content inscription, so the sealed field is a single GCM blob under one 12-byte nonce.

2.3. The sealed field is the inscription content. It MUST be placed in a valid 1Sat inscription envelope (BRC-159, BRC-160) as the content body, with a content type the owner chooses. An owner that wishes to conceal the true media type SHOULD inscribe a neutral content type such as application/octet-stream, because the content type is itself on-chain and world-readable.

2.4. A sealed ordinal MUST NOT carry a cleartext metadata section that would fingerprint the sealed content (for example its true name or type). Metadata placement for unsealed inscriptions is out of scope here.

3. The public reveal

3.1. A public reveal is one output whose script is exactly:

OP_FALSE OP_RETURN <push "TKORV1"> <push script_id> <push data_key> <push outpoint>

that is, bytes 0x00 0x6a, then a minimal push of the 6-byte ASCII tag TKORV1, a minimal push of the 32-byte script_id, a minimal push of the 32-byte reveal key data_key, a minimal push of the ASCII genesis outpoint ("<txid>:<vout>"), and nothing further.

3.2. The output MUST carry zero satoshis. It is provably unspendable: OP_RETURN fails script evaluation immediately, so no input can ever spend the output; the leading OP_FALSE makes the output a standard data carrier under common relay policy. The output exists only to publish the reveal payload.

3.3. script_id MUST equal SHA-256 of the sealed ordinal's inscription output script (section 1); data_key MUST be that ordinal's reveal key; and outpoint MUST be the ordinal's genesis outpoint, naming the output whose script hashes to script_id. A reader recomputes script_id from the ordinal it holds, matches it against published reveals, and reads the ciphertext from outpoint.

3.4. A parser MUST accept an output as a public reveal only when it is exactly the elements of 3.1: OP_FALSE, OP_RETURN, then exactly four data pushes, each a minimal push (the shortest encoding for its length), with the tag equal to TKORV1, the second and third pushes exactly 32 bytes, and the fourth a well-formed "<txid>:<vout>" ASCII outpoint (matching ^[0-9a-f]{64}:(0|[1-9][0-9]{0,9})$), and no trailing data. Any other shape is not a public reveal.

3.5. The tag TKORV1 is reserved by this specification and MUST NOT be reused by, or confused with, any other OP_RETURN protocol. In particular a public reveal is not a record in, and MUST NOT be ingested by, any timed-reveal or whistleblower feed, such as the timed disclosure of BRC-216; it carries no marker of any such feed, and its tag is disjoint from theirs.

3.6. Publishing a public reveal is irreversible: once the output confirms, the reveal key is world-readable permanently. There is no retraction.

4. The targeted reveal grant

4.1. A targeted reveal grant is a JSON object delivered off chain (over a private message, as a file, or as a QR). Its fields are:

  • magic: the ASCII string "TKRG1".
  • v: the integer 1.
  • script_id: the sealed ordinal's script_id, lowercase hex (64 characters).
  • outpoint: the sealed ordinal's genesis outpoint as "<txid>:<vout>".
  • recipient: the recipient's identity public key, compressed, lowercase hex (66 characters). The grant is signed over this field, so the owner attests the one recipient the grant is for.
  • key_commitment: SHA-256(reveal_key), lowercase hex (64 characters). The grant is signed over this field, so the owner attests the exact key the grant delivers, and it equals the commitment the sealed ordinal already carries (2.2).
  • owner: the owner's identity public key, compressed, lowercase hex (66 characters).
  • ts: an integer millisecond timestamp.
  • sig: the owner's signature over the signed range, per 4.3, DER-encoded, lowercase hex.
  • wrap: the reveal key and its recipient-only metadata wrapped to the recipient, per 4.4.

The sensitivity label, the true name, and the true media type of the content are recipient-only and ride inside wrap (4.4); they are deliberately absent from the cleartext grant. The object MAY carry additional fields; a verifier ignores unknown fields and MUST reconstruct the signed range of 4.3 from the named fields alone, never from the object as received.

4.2. A grant MUST be rejected before any further processing unless magic is the string "TKRG1"; v is the integer 1; ts is an integer; each of script_id, outpoint, recipient, key_commitment, owner, sig, and wrap is a JSON string; owner and recipient are each a valid 33-byte compressed secp256k1 public key on the curve; key_commitment decodes to 32 bytes; outpoint matches ^[0-9a-f]{64}:(0|[1-9][0-9]{0,9})$; and each string is within a sane length bound. A grant in which any binding field is a non-string value (for example a number) is malformed, so that a crafted grant cannot pass a signature check and then crash a consumer that treats the field as a string.

4.3. The signed range is the fixed, closed tuple of the eight fields magic, v, script_id, outpoint, recipient, key_commitment, owner, ts, all REQUIRED, reconstructed from the parsed grant (not the object minus wrap/sig). The owner MUST sign the bytes

D || 0x00 || canonical(signed_fields)

where D is the fixed ASCII domain-separation tag sealed-ordinal-reveal-grant-v1, 0x00 is a single separator byte, and canonical(x) is the deterministic JSON encoding of x: UTF-8, object keys sorted in ascending Unicode code-point order, no insignificant whitespace (item separator ,, key separator :), integers only (a floating-point, NaN, or Infinity value is a MUST NOT), strings escaped per RFC 8259 using only the mandatory escapes (", \, and the control characters U+0000 to U+001F) with every other character, including non-ASCII, emitted as literal UTF-8, and no duplicate keys. For the eight fields of the signed range the sorted key order is key_commitment, magic, outpoint, owner, recipient, script_id, ts, v. The signature is ECDSA over the secp256k1 curve by the owner's identity key over the SHA-256 digest of those bytes, produced with an RFC 6979 deterministic nonce, low-S normalized, and DER-encoded. The domain tag makes a grant signature valid only within this protocol, and a verifier that hashes the identical canonical bytes recovers the identical digest.

4.4. wrap is the base64 encoding of a "BIE1" ECIES encryption, to the recipient's compressed identity public key R, of the canonical JSON wrap envelope. The scheme is fixed to the byte:

  • The wrap envelope is canonical(P) (the encoding of 4.3) of an object P whose base-profile fields are v (the integer 1), key (the 32-byte reveal key, lowercase hex, 64 characters), classification (the owner's sensitivity label, a short lowercase ASCII token such as "sensitive" or "private"), name (the true title), and content_type (the true media type). For the base profile the sorted key order is classification, content_type, key, name, v. The minimum interoperable contract is that the opened envelope is a JSON object with v == 1 whose key is the 32-byte reveal key, lowercase hex.
  • The owner draws a fresh ephemeral private key e per wrap, with compressed public key E (33 bytes), and computes the ECDH shared point S = e * R as a compressed SEC point (33 bytes).
  • Key material is H = SHA-512(S): iv = H[0:16], key_e = H[16:32] (a 16-byte AES-128 key), key_m = H[32:64] (a 32-byte HMAC key).
  • The ciphertext is C = AES-128-CBC(key_e, iv, PKCS#7(envelope)).
  • The MAC is M = HMAC-SHA256(key_m, "BIE1" || E || C) (32 bytes).
  • The BIE1 blob is "BIE1" || E || C || M, where "BIE1" is the 4 ASCII bytes 0x42 0x49 0x45 0x31; wrap is its standard base64 encoding (RFC 4648 §4, with padding).

Only the holder of the recipient identity private key r opens it: it recomputes S = r * E, derives the same iv, key_e, key_m, verifies M, decrypts C, and un-pads. Because classification, name, and content_type ride inside the envelope, they are never in the cleartext grant and never on chain.

4.5. Any sealed ordinal MUST NOT carry an author-identity section (BRC-217), whether it is to be revealed publicly, by grant, or not at all. An author section publishes the owner's identity address in cleartext, and its recoverable signature yields the owner's identity public key, which would permanently and publicly link the sealed ordinal to the owner and defeat the seal. Authorship is a feature of public inscriptions only.

4.6. A grant is irreversible once delivered: there is no revocation. An owner that must prevent a reader from decrypting MUST NOT deliver the grant.

5. Verification

5.1. A public reader, holding a sealed ordinal and seeing a candidate public-reveal output, MUST: parse the output per 3.4; recompute script_id as SHA-256 of the ordinal's inscription output script (its genesis output, resolved as its origin per BRC-159); accept the reveal only if the parsed script_id equals the recomputed value; check that the BRC-369 commitment of data_key, SHA-256("metanet keyed content commitment v1" || data_key), equals the key_commitment in the ordinal's sealed field (2.2) and reject the key on mismatch; then derive the symmetric key SHA-256("metanet keyed content symmetric v1" || data_key), AES-256-GCM-decrypt the ordinal's ciphertext (the sealed field with the trailing commitment removed) under it, and accept the content only if the GCM tag verifies. These are the three checks of BRC-369 section 5.3, in order. A reader MUST treat a reveal whose script_id does not match as not applying to this ordinal, and on a failed commitment check or a failed tag MUST continue to consider other candidate reveals bearing the same script_id rather than concluding the ordinal is unrevealable, so a junk or poisoned output cannot suppress the genuine key.

5.2. A targeted recipient, holding a grant, MUST: reject the grant unless 4.2 holds; verify sig over the signed range of 4.3 against the owner key, and reject on failure; open wrap with the recipient identity private key to obtain the envelope, and reject if it is not a v == 1 envelope carrying a 32-byte key; reject unless the BRC-369 commitment of key equals the signed key_commitment; read the output script at outpoint from the chain; reject unless SHA-256 of that script equals script_id; parse the inscription from that script and reject if it carries none; then derive the symmetric key from key, AES-256-GCM-decrypt the ciphertext under it, and accept only if the tag verifies. The recipient needs neither the owner's seed nor any indexer.

5.3. Both parties derive the binding (script_id) from the ordinal itself and the key commitment from the key, so a reveal and an ordinal either match or do not, and a key either is or is not the committed one, with no third party consulted.

6. Summary of requirements

Owner (sealing): generate a fresh BRC-369 content key k, a secp256k1 scalar, from a secure source (2.1); seal as nonce||ciphertext||tag||key_commitment with a 12-byte nonce and no associated data, the symmetric key and the commitment being BRC-369's two domain-separated hashes of k (2.2); inscribe the sealed field in a valid 1Sat envelope, with a neutral content type when hiding the media type (2.3); carry no fingerprinting cleartext metadata (2.4); attach no author section (4.5).

Owner (public reveal): emit exactly OP_FALSE OP_RETURN "TKORV1" <script_id:32> <data_key:32> <outpoint> (3.1); zero value (3.2); script_id, data_key, and outpoint correct (3.3); the tag reserved and feed-isolated (3.5).

Owner (targeted reveal): build the grant fields of 4.1 with 4.2's types; sign the closed 4.3 range under domain sealed-ordinal-reveal-grant-v1; wrap the envelope (with the 32-byte key, classification, name, and media type) to the recipient per 4.4; attach no author section (4.5).

Public reader: parse strictly with minimal pushes (3.4); match script_id, check the key commitment, and verify the GCM tag before trusting content, falling through on failure (5.1).

Targeted recipient: reject a malformed or wrongly typed grant (4.2); verify the owner signature; open the wrap; check the key against the signed commitment; match script_id at the named outpoint; then decrypt and verify the tag (5.2).

Security considerations

Confidentiality rests entirely on the reveal key. Until a reveal, the on-chain ciphertext, the content type, and the key commitment are all an observer has; AES-256-GCM under a fresh random key leaks nothing about the content, the authentication tag detects any modification of the ciphertext, and the commitment is a one-way hash of the key. The content type SHOULD be neutral when the media type is itself sensitive (2.3). The ciphertext length equals the plaintext length plus a fixed overhead, so it discloses the exact plaintext size; an owner that regards the size as sensitive SHOULD pad the content to a bucket before sealing.

One content, one key. AES-256-GCM is not key-committing: without the commitment a sealer who controls the ciphertext and the keys could craft one sealed field that opens to two different valid plaintexts under two different keys. The key_commitment in the sealed field (2.2), checked by a public reader (5.1), and the same commitment signed into a grant (4.3) and checked by a recipient (5.2), fix the single key that opens the ordinal, so a sealer cannot equivocate between a public reveal and a grant, or between two grants.

Both reveals are irreversible. A public reveal is permanent chain data; a targeted grant, once delivered, cannot be recalled. The only supported transition is from sealed to revealed; there is no path back, and the transition has no inverse because a party that has learned a key cannot be made to unlearn it and chain data is permanent. Containment of a targeted reveal is behavioral, not cryptographic: a recipient who has the key can always publish a public reveal or forward the key, and nothing in this protocol prevents that.

Binding prevents a key from being applied to the wrong ordinal: script_id is a second-preimage-resistant hash of the exact inscription output script, so a reader that matches it is decrypting the intended ordinal. A grant additionally binds to the outpoint, the recipient, and the key_commitment, and is owner-signed over all of them. Because recipient is signed, a holder of the key cannot re-wrap it to a different party and forward the owner's unchanged signature: the signature is valid only for the recipient the owner named. Because key_commitment is signed, a substituted wrap that carries a different key is detected on open.

A grant signature proves knowledge of the owner identity private key over the bound fields; it does not prove that the signer created or owns the underlying content, and the owner field is self-asserted, so a recipient that needs to know who the owner really is confirms that identity key out of band. The signature is a direct, universally verifiable attestation: anyone who later obtains the grant can prove to a third party that this identity key granted this ordinal to this recipient at this time. This non-repudiation is intended for the credential and evidentiary cases, but it is also a transferable, retained proof of the owner's act; an owner for whom that proof is itself sensitive MUST treat a delivered grant as sensitive material and weigh that a coerced or hostile recipient can present it.

Identity leakage is limited by three rules. A sealed ordinal carries no author section (4.5), so sealing never publishes the owner's identity. A grant keeps the classification, the true name, and the media type inside the recipient-only wrap (4.4), so an intercepted grant blob leaks none of them and none of the content. An intercepted grant does, however, carry in cleartext the owner identity key, the recipient identity key, the script_id, the outpoint, and ts: it therefore reveals that this owner granted this specific ordinal to this specific recipient at this time. A grant SHOULD be delivered over a confidential, authenticated channel for this reason. Publishing a public reveal, likewise, deanonymizes the revealer through the funding of the reveal transaction; an owner that wishes to reveal unlinkably SHOULD fund it from coins not tied to their identity.

Feed isolation (3.5) keeps a reveal out of unrelated OP_RETURN feeds. The reserved tag TKORV1 is distinct from any timed-reveal or whistleblower tag, so a reveal is never counted as a firing or a record elsewhere.

Malformed-input hardening (4.2) ensures a grant relayed by an untrusted party is either a valid grant or rejected as not a grant, never a value that passes the signature check and then crashes a consumer; the length bounds keep a hostile grant from carrying an unbounded field.

Mathematical and cryptographic basis

Symmetric sealing uses AES-256-GCM, an authenticated encryption scheme: for a 256-bit key K, a 96-bit nonce N chosen fresh per message, and plaintext P, it produces (C, T) with C the same length as P and T a 128-bit tag, such that decryption returns P only if (C, T) is unmodified under K and N. Here K is the symmetric key SHA-256("metanet keyed content symmetric v1" || k) derived from the content key k (BRC-369 section 2.1.3), not k itself. The sealed field is N || C || T || SHA-256("metanet keyed content commitment v1" || k). Nonce freshness is required: under a repeated (K, N) GCM discloses the XOR of the two plaintexts and the authentication subkey. Because k is fresh per ordinal (2.1), a nonce repeat requires a key repeat across two ordinals, which is forbidden, and would damage both affected sealings and no others.

The commitment is SHA-256("metanet keyed content commitment v1" || k) (BRC-369 section 2.2, digest form). By preimage resistance it discloses nothing about the content key k; by collision resistance the owner cannot find a second k with the same commitment, so the committed key is the only key a verifier will accept for that ordinal. Its domain string differs from the symmetric key's (BRC-369 section 2.2.3), so publishing it reveals neither k nor the AES key. This is BRC-369's commitment, reused; it is what turns the non-committing GCM field into a one-content, one-key object.

The binding is script_id = SHA-256(s) for the inscription output script s. SHA-256's collision and second-preimage resistance mean a reader that finds SHA-256(s) equal to a published script_id is, except with negligible probability, holding the exact script the owner sealed, so the matched key is the right key for that ordinal.

The targeted wrap is "BIE1" ECIES to the recipient's secp256k1 identity key R = r*G: the owner draws an ephemeral scalar e, forms the shared point S = e*R = r*(e*G), derives (iv, key_e, key_m) from SHA-512 of the compressed S, encrypts the envelope with AES-128-CBC under key_e, and authenticates "BIE1" || e*G || C with HMAC-SHA256 under key_m. Only the holder of r recomputes S = r*(e*G) and decrypts. The ephemeral key per wrap gives a fresh shared secret each time; the MAC over the ciphertext and the ephemeral public key provides the integrity the CBC mode lacks on its own.

The grant signature is ECDSA over secp256k1 by the owner's identity key d over the digest of D || 0x00 || canonical(signed_fields). The curve is the standard secp256k1: the field prime p = 2^256 - 2^32 - 977, the generator G, and the prime order n, with a key pair (d, d*G) for 0 < d < n. Domain separation by the fixed tag D means the signed bytes of this protocol never coincide with those of another, so a signature produced here is not valid anywhere else, and the canonical encoding means the owner and every verifier hash the identical bytes. The RFC 6979 deterministic nonce removes the random-k failure that leaks the private key on nonce reuse, and low-S normalization fixes a single encoding per (d, digest). Verification checks the signature against the stated owner public key, so a valid signature proves the signer held d and that the eight bound fields are exactly as signed; it does not by itself establish who controls that identity or who authored the content.

Assumptions and edge cases

Security rests on standard assumptions: AES-256-GCM is a secure authenticated cipher under a never-repeated (key, nonce); SHA-256 is collision- and second-preimage-resistant; SHA-512 is a secure KDF over the ECDH secret; ECDSA over secp256k1 is existentially unforgeable; and the BIE1 ECIES instantiation is secure against chosen-ciphertext attack. A reveal key is 256 bits, so brute force is infeasible; the only disclosure paths are the two this document defines. The binding is a hash of the exact scriptPubKey bytes, so an ordinal re-locked by a standard transfer (a new output script) has a different script id, and a reveal for the genesis script does not match a later re-locked output; the outpoint therefore names the genesis output, and both reveals resolve the ciphertext there. The irreversibility is computational and physical, not information-theoretic: once a key is disclosed it cannot be withdrawn, and on-chain data is permanent, so the sealed-to-revealed transition has no inverse.

Test Vectors

Every vector below was produced and checked against a reference implementation: the sealed field decrypts, under the symmetric key derived from the content key, back to the plaintext and its commitment matches the key, the public-reveal output parses and round-trips, the grant signature verifies against the owner key, and the wrap decrypts back to the reveal key and its envelope. The AES-256-GCM ciphertext (fixed key and nonce) and the ECDSA signature (RFC 6979 deterministic) reproduce these byte strings exactly. The BIE1 wrap uses a fresh ephemeral key per call in practice; the vector below fixes the ephemeral key so it, too, is a reproducible byte string.

Keys and inputs

  • Owner identity private key: SHA-256("sealed-reveal-owner"); compressed public key 0288b121a146a47c669a068f4393c5f31db931649b6781678775c2a88295dfcf5f.
  • Owner spend lock (P2PKH of the owner key): 76a914fec6399e8372d0d1e33a7bae1c51fa60321420f688ac.
  • Recipient identity private key: SHA-256("sealed-reveal-recipient"); compressed public key 025a802d3f17d2bfa777b5025e8c1a245863d2b446d8ab9476b7455f3a8299e356.
  • Content (plaintext): the ASCII bytes sealed ordinal content vector.
  • Reveal key, the BRC-369 content key k (32 bytes): ae1daaa8c71b1c98dbe9ff85c3995b1d3eb2dfe123ce1ecc223591e6a5a21b9c.
  • Symmetric key (SHA-256("metanet keyed content symmetric v1" || k)): 8ff2f8678007986d50d2fb15da8058e3736695c458745404b0210a856ada50f7.
  • GCM nonce (12 bytes): 000102030405060708090a0b.
  • Key commitment (SHA-256("metanet keyed content commitment v1" || k)): 759c4f37b144f98eabcd42bc03aea46cc4b26894e6cf7ca5ff5265b3fe788df7.
  • Genesis outpoint: abababababababababababababababababababababababababababababababab:0.
  • Grant timestamp: 1730000000000.

The sealed field and the sealed ordinal

Sealed field (nonce || ciphertext || tag || key_commitment, 60 bytes longer than the content):

000102030405060708090a0b1e562757b6ce3902c0daf309f98b5919feb2b0340125ab9c815a4f3da53f0aca451d3745f3d8a2b345720ab48c759c4f37b144f98eabcd42bc03aea46cc4b26894e6cf7ca5ff5265b3fe788df7

Inscription output script (owner lock, then the envelope carrying the sealed field under content type application/octet-stream):

76a914fec6399e8372d0d1e33a7bae1c51fa60321420f688ac0063036f726451186170706c69636174696f6e2f6f637465742d73747265616d004c59000102030405060708090a0b1e562757b6ce3902c0daf309f98b5919feb2b0340125ab9c815a4f3da53f0aca451d3745f3d8a2b345720ab48c759c4f37b144f98eabcd42bc03aea46cc4b26894e6cf7ca5ff5265b3fe788df768

Script id (SHA-256 of that script): 0e5d1c0f30460fb85e7a72c994284831167273d6274de8f538f80e65100eeaca.

Case A: the public reveal (TKORV1)

The reveal output script for the script id, reveal key, and outpoint above:

006a06544b4f525631200e5d1c0f30460fb85e7a72c994284831167273d6274de8f538f80e65100eeaca20ae1daaa8c71b1c98dbe9ff85c3995b1d3eb2dfe123ce1ecc223591e6a5a21b9c42616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261623a30

This is OP_FALSE OP_RETURN, a 6-byte push of TKORV1, a 32-byte push of the script id, a 32-byte push of the reveal key, and a 66-byte push of the ASCII outpoint. A reader parses it, recomputes the script id from the ordinal it holds, matches, checks the BRC-369 commitment of data_key against the sealed field's commitment, derives the symmetric key, reads the ciphertext at the outpoint, and decrypts to the plaintext.

Case B: the targeted grant signature (TKRG1)

The signed range (the eight fields in canonical, code-point-sorted order):

{"key_commitment":"759c4f37b144f98eabcd42bc03aea46cc4b26894e6cf7ca5ff5265b3fe788df7","magic":"TKRG1","outpoint":"abababababababababababababababababababababababababababababababab:0","owner":"0288b121a146a47c669a068f4393c5f31db931649b6781678775c2a88295dfcf5f","recipient":"025a802d3f17d2bfa777b5025e8c1a245863d2b446d8ab9476b7455f3a8299e356","script_id":"0e5d1c0f30460fb85e7a72c994284831167273d6274de8f538f80e65100eeaca","ts":1730000000000,"v":1}

The signed bytes D || 0x00 || canonical(signed_fields) are:

7365616c65642d6f7264696e616c2d72657665616c2d6772616e742d7631007b226b65795f636f6d6d69746d656e74223a2237353963346633376231343466393865616263643432626330336165613436636334623236383934653663663763613566663532363562336665373838646637222c226d61676963223a22544b524731222c226f7574706f696e74223a22616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261626162616261623a30222c226f776e6572223a22303238386231323161313436613437633636396130363866343339336335663331646239333136343962363738313637383737356332613838323935646663663566222c22726563697069656e74223a22303235613830326433663137643262666137373762353032356538633161323435383633643262343436643861623934373662373435356633613832393965333536222c227363726970745f6964223a2230653564316330663330343630666238356537613732633939343238343833313136373237336436323734646538663533386638306536353130306565616361222c227473223a313733303030303030303030302c2276223a317d

and the owner's DER signature over the SHA-256 digest of those bytes is:

30440220798faf2dd6a77957f79566b9eb7df1b2ecee65293651ec4eec79feb00db0e761022041775713b4387d92fc85753d1a9db605084cfb12e8cf1d00b8244a885b7a1f0f

Case C: the key wrap (BIE1 ECIES, fixed ephemeral)

The wrap envelope (canonical JSON, code-point-sorted) carried as the BIE1 plaintext:

{"classification":"sensitive","content_type":"application/pdf","key":"ae1daaa8c71b1c98dbe9ff85c3995b1d3eb2dfe123ce1ecc223591e6a5a21b9c","name":"deed","v":1}

With the fixed ephemeral private key SHA-256("sealed-ordinal-reveal-wrap-ephemeral") (compressed public key 03c6d3efc8e37bdc019317a493aed1826413ba0bc53c1bcd37a198f2414919fa51), the wrap (base64 of "BIE1" || ephemeral_pubkey || AES-128-CBC ciphertext || HMAC-SHA256) is:

QklFMQPG0+/I43vcAZMXpJOu0YJkE7oLxTwbzTehmPJBSRn6UaPXlgd06BKxPH3p5Vv7MA5YI8ba0g0halnKDXrT4lcSDMH+724CBWFByxROMAYQSUXP8dpoQO/46N1P/Nu8uD1bDQDjKLUcX/pAeZXO4fqx8pc+GtZTUZX/3m/odMJhaayMkoehse9kkrpl7MC8EPFn8io3RflNyFAktETeOd8y3+EPhdpHIQL8VJcAygMOfB0OF6LTkylWoA8Yjz4uFgw25RUwb41eH5D4SLzjxVDeyftVFFFTXH2FX3v4D7S9HA==

The recipient opens it with its identity private key to recover the envelope and the 32-byte reveal key.

Failing cases

  • Case A's output with any trailing byte appended, with a non-minimal push, or with a malformed outpoint, parses as not a reveal.
  • Case B's signature verified against any domain other than sealed-ordinal-reveal-grant-v1 fails.
  • A grant whose outpoint, or any binding field, is a JSON number rather than a string is rejected before the signature is checked.
  • A grant whose wrap carries a key other than the one named by the signed key_commitment is rejected on open even though the signature verifies.
  • A grant whose recipient is changed (and wrap re-aimed) fails signature verification, because recipient is in the signed range.

References

Relied upon:

Related, cited only to position this specification and not relied upon for interoperation:

Implementations

A reference implementation produces and consumes all four forms (the sealed ordinal, the public reveal, the targeted grant, and the key wrap) and generated the vectors above.