Beersy
BRC-248Draft (proposed number, not a BSVA assignment)

Offline Issuer Identity Packages

When a wallet shows you who issued an item, all it usually has is a public key, a string of letters nobody recognizes. Getting a real name and picture for that key has meant trusting a web link that can rot or change, or calling out to a server every time you want to show it, which fails the moment that server is down or lying. This makes it possible to show a trustworthy name and image for an issuer using only data the wallet already has, with no live lookup required.

Brandon Cryderman / HandCashchanged 13 Oct 202615 min read

Reference for an AI

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

Summary

Why
A bare public key does not tell a person who issued something, and every existing way to attach a name or picture to that key either depends on a server staying online, duplicates image bytes everywhere, or lets anyone forge the claim.
What
BRC-248 defines an offline identity package, a small of , image bytes and an optional linked BAP profile that a wallet uses to show a name and picture for an issuer's without any live lookup.
How
A wallet stores one package per identity key, verifies the certificates and image hashes inside it, picks a using the spec's fixed source order (trusted certificate, other trusted certificate, linked BAP profile, self-published certificate), always shows who is vouching for that label, and may hand the…

What this lets you do

  • Build a small, size-capped identity package for an issuer's public key
  • Pick a display name from certificates, a BAP profile or a self-published claim using a fixed priority order
  • Carry an image's actual bytes alongside a content hash so it renders without a network fetch
  • Link a BAP identity to a BRC-100 identity key with a two-signature record
  • Attach up to two identity packages to a delivery message without putting them inside the item's

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

identity keyBAP keylink recordprofile

The specification

Abstract

BRC-247 stamps a 1Sat or 1Color issuance with the issuer's BRC-100 . This BRC lets a holder turn that identity key into a name and an image from data it already holds, without querying an indexer, an or a web server at display time.

  • An identity package is a small object that carries what names an identity key: BRC-169 , publicly revealed BRC-52 certificates, the image bytes they point to, and optionally a BAP profile linked to the identity key.
  • A reader chooses a from these in a fixed order and always shows who vouches for it.
  • Wallets store one package per identity key and attach it to item deliveries only when the receiver needs it. Assets carry only the identity key.

This BRC adds no identity format. The identity is the identity key; certificates are , handles are BRC-169, and BAP profiles are BAP.

Motivation

A bare public key means nothing to a person, so wallets want a name and a picture for each issuer, and each common source of one falls short:

  • A URL icon binds a location, not bytes. The image can change or disappear after signing.
  • A self-signed JSON profile copied into every mint duplicates bytes in each asset and leaves every wallet to invent freshness rules.
  • A lookup at display time, in an indexer or an identity overlay, makes showing an asset depend on that service being reachable and honest, the dependency BRC-150 removes for item provenance.
  • An identity ordinal (an inscription holding the profile) puts the profile on a that can be sold or moved, and moving it carries no authority.

Signed statements about identity keys already exist. A BRC-169 ecosystem certifies each handle to an identity key; the identity overlay (tm_identity) publishes BRC-52 certificates whose fields are revealed to anyone; 1Sat wallets publish BAP ALIAS profiles. Offline use still needs four rules: which of these count, which label wins, how image bytes travel, and how a BAP profile attaches to an identity key without becoming a second identity.

Relationship to other documents

  • BRC-247: the issuer stamp, which names the identity key this BRC labels.
  • BRC-52: certificates, verifier and .
  • BRC-169: handle certificates (§4.1), their (§5.1) and reverse resolution (§5.10), from which a wallet obtains a peer's handles.
  • BRC-26: , content-addressed URLs used for certificate images.
  • BAP, AIP and B://: the optional BAP profile, its record signatures and its image.
  • BRC-62: , the carrier of BAP records.
  • BRC-150 and BRC-176: the proofs that carry an asset's stamped transaction.
  • BRC-37: compact claims in customInstructions.
  • BRC-33: store-and-forward delivery.

Specification

The key words MUST, SHOULD and MAY are used as in RFC 2119.

1. Identity package

{
  "v": 2,
  "identityKey": "<compressed public key, lowercase hex>",
  "certificates": [ <certificate>, … ],
  "images": [ { "url": "<UHRP URL>", "contentType": "<media type>", "bytesB64": "<base64>" }, … ],
  "bap": { "bapId": "<BAP ID>", "beefB64": "<base64 BEEF>" }
}
  • Only v and identityKey are required. A package names exactly one identity key.
  • The serialized package MUST be at most 163,840 bytes. It carries at most 8 certificates and at most 2 images.
  • certificates are section 2's certificates; images are section 3's image bytes; bap is section 5's linked BAP profile.

Packages with v: 1, written by earlier drafts, carried only BAP records keyed by a BAP ID. A reader MAY use one as the bap member of whichever identity key a valid link (section 5) names, and otherwise MUST ignore it.

2. Certificates

Each entry is a BRC-52 certificate whose fields are revealed to anyone: the core certificate with a keyring addressed to the anyone key (private key 1), as the identity overlay publishes it. A reader:

  1. MUST verify the certifier's signature over the core certificate, and drop the certificate if it fails.
  2. MUST require subject to equal the package's identityKey.
  3. MUST decrypt the revealed fields with the keyring; fields that are not revealed are absent.
  4. MUST verify a BRC-169 handle certificate as BRC-169 §4.1 requires, except for revocation (below), with a certifier key the reader already holds for that domain. It MUST NOT trust a certifier key carried in the package.

A certificate is a claim by its certifier. A reader decides which certifiers it trusts, and MUST show the certifier beside any label taken from a certificate. A certificate whose certifier is its subject is self-published.

Revocation. Whether a certificate's revocationOutpoint is spent cannot be proven from the package. A reader that can reach a revocation source SHOULD check it, as BRC-169 §4.2 describes, and MUST drop a revoked certificate. Without one, a reader MAY show the label as of the package and MUST NOT use a package certificate for a value-moving decision.

Fields. A reader takes a name and an image from a certificate's revealed fields:

CertificateNameImage
BRC-169 handleThe handle, displayed per BRC-169 §2.4—
Any othername; else userName; else firstName and lastName joined by a spaceprofilePhoto; else icon; else avatar

A name MUST be 1 to 80 characters, with no control characters and no leading or trailing whitespace; otherwise the certificate supplies no name. Email addresses and phone numbers MUST NOT be shown as names.

3. Images

Certificate image fields are URLs. Readers MUST NOT fetch an http(s) URL. A UHRP URL names content by its SHA-256 (BRC-26), so the package can carry the bytes:

  • url is the UHRP URL as it appears in the certificate field. A reader MUST check that the SHA-256 of the decoded bytes equals the hash the URL encodes, and drop the image otherwise.
  • contentType MUST be image/webp, image/png or image/jpeg, and the image MUST be 1 to 65,536 bytes.
  • Readers MAY accept an inline data: image within the same limits.

Writers SHOULD re-encode the source image, removing EXIF and other metadata, and SHOULD use a square image of at most 512 px.

4. Choosing a label

A reader shows one name for an identity key, taken from the first source that supplies one:

  1. A verified handle certificate from a certifier the reader trusts.
  2. Another verified certificate from a certifier the reader trusts.
  3. A linked BAP profile (section 5).
  4. A self-published certificate.
  5. None: the reader shows the identity key, for example as a short fingerprint.

Where one source holds several candidates, the reader's certifier preference decides; package order MUST NOT. The image comes from the first of sources 2 to 4 that supplies a valid one. A reader MUST show where the label came from: the certifier, "BAP profile" or "self-published". Labels from sources 3 and 4 are claims by the issuer about itself.

5. Linked BAP profile

A BAP identity is shown as an identity key's profile only when both sign one link record:

OP_FALSE OP_RETURN
  1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 SET type identity-link identityKey <identity key> bapId <BAP ID>
  | SIGMA BRC77 <identity key address> <signature> <vin>
  | SIGMA BSM <BAP signing address> <signature> <vin>
  • The first SIGMA is by the identity key, as BRC-247 signs; the second is by a BAP signing key and signs over everything before it, the first SIGMA included. Both bind to the same input vin, and verifiers MUST reject a vin of -1.
  • A link is valid when both signatures verify, identityKey equals the key in the first signature, and the second signer's (section 6) is active at the link's mined height.
  • Either party ends a link with an identity-unlink record: the same MAP tape with type identity-unlink, and one SIGMA by either the identity key or an active BAP signing key. A BAP revocation also ends every link of that identity.
  • If an identity key has several valid links, the latest mined one wins, and two at the same height cancel each other. One BAP identity MAY link several identity keys, such as the accounts of one vault.

The bap member's BEEF contains the link record, the records section 6 builds the key chain from, the ALIAS section 7 selects, the B file it names, any unlink record and any revocation. Each mined transaction MUST carry its . Heights decide rotation, links and revocation, so before storing a package received from someone else a reader MUST check every in it against , for example with an chain tracker, and MUST NOT store a package whose roots it cannot check.

A stamp from an earlier draft of BRC-247, signed by a BAP key, is attributed to an identity key only when that BAP identity is linked to it and the stamp's signer is active at the asset's mined height.

6. BAP records and key chain

BAP records are OP_FALSE OP_RETURN data outputs, so they are unspendable. Writers SHOULD create them with 0 .

ID     OP_FALSE OP_RETURN 1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT ID <bapId> <address>
       | 15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva BITCOIN_ECDSA <signer address> <signature>
ALIAS  OP_FALSE OP_RETURN 1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT ALIAS <bapId> <profile JSON>
       | 15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva BITCOIN_ECDSA <signer address> <signature>
B      OP_FALSE OP_RETURN 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut <image bytes> <content type> binary

AIP signature

  • It signs the OP_RETURN byte (0x6a), then the data of every push before the | separator, concatenated without their push opcodes, then the | byte (0x7c).
  • It is a BSM compact signature. Writers MUST carry it as 65 raw bytes, as 1Sat wallets do. Readers MUST also accept the 88-character base64 text of those bytes, which the AIP specification and earlier BAP libraries write.
  • A reader MUST recover the public key from the signature and check that its address equals <signer address>. A record whose signature does not verify MUST be ignored.
  • A record MUST contain exactly two protocols: BAP and AIP.

BAP ID and root address. bapId is base58(ripemd160(sha256(utf8(rootAddress)))), as BAP defines. The root address is the signer of an ID record whose signer address hashes to bapId. Readers MUST NOT accept a root address that does not hash to the BAP ID.

Key chain. From the records for one BAP ID:

  1. Find the root address.
  2. Let current be the root. Among ID records signed by current that declare a valid address other than 0, take the first on chain (below). That address is the next signing key. Set current to it and repeat.
  3. Stop when there is no candidate or when an address repeats. Readers MUST follow at least 64 keys and MAY stop after that.
  4. The last key in the chain is the current key. A chain with no declared key is not an identity.

First on chain. A record has a mined height when the package proves it with a merkle path; otherwise it is unmined. If any candidate is mined, the lowest height wins, and two mined candidates at the lowest height have no winner, so the chain stops there. If no candidate is mined, a single unmined candidate wins; two or more have no winner.

Revocation. As BAP defines, an ID record signed by the root address that declares the address 0 destroys the identity. Readers use the first-on-chain revocation, or any revocation when none wins. ID records not signed by the root that declare 0 are ignored.

Signer verdict. Whether a key spoke for the BAP identity in a block at height h (unknown when unmined or unproven) is the first row that applies:

VerdictWhen
unknown-keyThe key is not in the chain.
revokedA revocation exists, and it is unmined, h is unknown, or h ≥ the revocation's height.
activeThe key is the current key, its successor is unmined, or h is known and lower than its successor's height.
retired-keyOtherwise.

Only active counts. A rotation does not undo links signed before it was mined, and an unconfirmed revocation takes effect at once.

7. BAP profile

The ALIAS body is a JSON object using schema.org Person or Organization attributes. name follows section 2's rule; description is OPTIONAL, at most 280 characters, and an invalid one is dropped. image SHOULD be b://<txid>, naming a B output in the BEEF; a B file follows section 3's type and size limits.

An identity can have many ALIAS records. Readers consider only those whose signer is active at the ALIAS's own height, and rank them in order:

  1. An ALIAS signed by a later key in the chain ranks above one signed by an earlier key.
  2. For the same key, an unmined ALIAS ranks above a mined one.
  3. Between two mined records, the higher block ranks first.
  4. In the same block, an ALIAS in the same transaction as the ID record declaring its signer ranks lower.
  5. Otherwise, the higher transaction offset within the block ranks first.

If the top ALIAS has no valid name, the reader tries the next one. BEEF serialization may reorder transactions, so readers MUST NOT use package order to choose a profile.

8. Store once

  • Wallets SHOULD store one package per identity key and resolve every stamp through that store.
  • Wallets MUST NOT copy a package into an item's remittance or .
  • When a package arrives for an identity key already stored, a wallet SHOULD merge them: the union of certificates and images, and the union of BAP records re-evaluated under sections 5 to 7. A peer that leaves out a rotation, an unlink or a revocation then cannot hide it.
  • Wallets SHOULD keep packages for identities they control indefinitely and include them in the user's identity backup. They MAY cap the number stored from peers, evicting the oldest-stored first.
  • A wallet obtains a peer's handle certificates from BRC-169 reverse resolution or from the peer, and MAY refresh a stored package that way; the label does not wait for it.

9. Delivery beside an item

No BRC defines the message a wallet sends with an item or token over a BRC-33 . When that message body is a JSON object, its meta object (created if absent) MAY carry packages for the identity keys the delivered assets name. Receivers that do not implement this BRC ignore the member.

{ "meta": { "identities": [ <identity package>, … ] } }
  • A sender MUST NOT attach more than 2 packages to one envelope.
  • Within the box size cap, the Atomic BEEF and the item's BRC-150 provenance come first. A sender adds packages last and omits any that do not fit.
  • The receiver verifies and stores packages (sections 2 to 8). Packages MUST NOT gate item ingest, payment internalization or message acknowledgement, and MUST NOT be stored in a chat transcript.
  • Packages MUST NOT be placed inside an item's Atomic BEEF; BRC-95 Atomic BEEF holds only the subject transaction's ancestry.

10. Wallet baskets

A wallet keeps the BAP records of its own BAP identity in bap, as 1Sat wallets do:

RecordTagscustomInstructions
IDtype:id, bapId:<id>, seq:<N>{"protocolID":[1,"sigma"],"keyID":"identity-<N>"}
ALIAStype:alias, bapId:<id>, publishedAt:<ms>—
B filetype:image, bapId:<id>—
Link or unlinktype:link, bapId:<id>, identityKey:<key>—

BAP key N is the BRC-42 child at protocol [1, "sigma"], identity-N, self; key 0 is the root. 1Sat wallets take the ID record with the highest seq: in bap as declaring the wallet's current BAP key, so bap MUST hold only the BAP identity derived from the wallet's own root; records of any other BAP identity go in another basket, with the same tags and no customInstructions. Before signing a link, a wallet merges the records other apps added to bap, so it never signs with a BAP key another app has rotated away.

Tags are filters, not records. Reference BRC-100 clients lowercase tags, and a BAP ID is case-sensitive base58, so readers MUST match bapId: case-insensitively and MUST take the BAP ID from the record script. These are data outputs, not collectables, and wallets MUST NOT list them in a collectable view.

Rationale

The identity key, labelled by certificates. The identity key is what BRC-247 stamps and what BRC-100 applications already address. Handles and identity certificates are existing signed statements about identity keys, so labelling needs no new identity object, only rules for carrying and ranking them.

Who vouches is always shown. A certificate is only as good as its certifier, and a self-published name is only a claim. Showing the source beside the label lets a holder tell a certified handle from a name anyone could write.

A two-way BAP link. A link signed only by the identity key would let anyone claim someone else's BAP profile; one signed only by the BAP key would let a BAP identity attach itself to someone else's assets. Requiring both keeps BAP a profile of the identity key, never a second issuer.

Image bytes by hash. UHRP URLs already name content by hash, so carrying the bytes lets the image render offline and lets the reader prove they are the bytes the certifier signed.

Package beside items, not inside them. Copying an image into each item wastes space, and putting the package inside Atomic BEEF is forbidden by BRC-95.

Security considerations

  • Permanence and privacy. Published names, images and BAP records are public and permanent. Writers SHOULD warn the user before publishing and SHOULD strip image metadata such as GPS location.
  • Certifier trust. A certificate proves what its certifier signed, not that the certifier is honest. Readers choose their certifiers and pin their keys; a certifier key carried in a package proves nothing.
  • Stale certificates. Revocation is not provable offline. A package can show a handle released after it was written, so readers re-check when online and never use a package certificate for a value-moving decision.
  • Look-alike names. A self-published name or BAP profile can imitate a known issuer. Readers SHOULD apply BRC-169 §2.3's confusable checks and SHOULD show the identity key's fingerprint beside self-published labels.
  • Forks outside the package. A reader with no prior package sees only the BAP records it receives, so a rotation or unlink the sender leaves out is invisible to it until a merge supplies it.
  • Forged heights. A BAP member could claim proofs for blocks that do not exist; section 5 requires a header check before storing it.
  • Resource limits. Readers SHOULD enforce the image and package limits before decoding, decode images in a sandboxed renderer, and bound the number of stored peer packages.
  • Copied claims. Anyone can write issuer <key> into their own script. Only a BRC-247 stamp that verifies names an issuer, and only a valid link attaches a BAP profile.

Reference implementation

HandCash Desktop (@handcash/wallet-ui):

  • src/wallet/handleCertificate.ts: BRC-169 handle certificate verification with pinned certifiers.
  • src/wallet/bapRecords.ts and src/wallet/issuerIdentity.ts: BAP records, AIP verification, key chain, signer verdict and profile selection.
  • src/wallet/issuerIdentities.ts: the package store and header check.
  • src/wallet/issuerIdentityDelivery.ts and src/wallet/messageTransport.ts: envelope attach and receive.

Version 2 packages, publicly revealed certificates and link records are in progress there.

Was this helpful?

Search Beersy

Search standards by number, title, author or topic