> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/peer-to-peer/0052.md).

# Identity Certificates

* Brayden Langley (<brayden@projectbabbage.com>)
* Ty Everett (<ty@projectbabbage.com>)

## Abstract

This specification defines identity certificates for BRC-100 wallets and peer-to-peer authentication systems. A certificate binds an identity key to encrypted certified fields under a certifier signature, while allowing the holder to reveal selected fields to selected verifiers. The specification covers the core certificate JSON and binary formats, the signed binary preimage, certificate field encryption, master keyrings, verifier keyrings, and revocation outpoints.

This specification is authoritative for certificate primitives used by [BRC-100](/wallet/0100.md), [BRC-103](/peer-to-peer/0103.md), and [BRC-104](/peer-to-peer/0104.md). Older certificate descriptions in Authrite-era specifications, including BRC-31, BRC-53, and BRC-56, are not normative for BRC-100 certificate behavior.

## Motivation

Digital signatures prove control of keys, but applications also need a privacy-preserving way to verify claims about the controller of a key. Identity certificates provide that linkage without requiring the holder to reveal every certified attribute to every verifier. The certifier signs encrypted field values, so the certificate remains tamper-evident even when no fields are revealed. The holder can later provide encrypted field-revelation keys for only the fields a verifier is allowed to inspect.

## Terminology

* **Subject**: The identity key whose holder is certified.
* **Certifier**: The identity key that signs the certificate.
* **Verifier**: A party receiving a certificate and optionally receiving keys for selected fields.
* **Core certificate**: The signed certificate fields, excluding all keyrings.
* **Master certificate**: A core certificate plus a master keyring that lets the subject or certifier decrypt all certificate fields.
* **Verifiable certificate**: A core certificate plus a verifier keyring that lets a specific verifier decrypt selected certificate fields.
* **Field revelation key**: A random 32-byte symmetric key used to encrypt one certificate field value.
* **Keyring**: A map from field names to encrypted field revelation keys.

The key words "MUST", "MUST NOT", "SHOULD", and "MAY" are to be interpreted as normative requirements.

## Primitive Types

| Type                      | JSON representation    | Binary representation                                   | Requirements                                                                                                                                                                |
| ------------------------- | ---------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CertificateTypeID`       | Base64 string          | 32 bytes                                                | Identifies the certificate type. Certificates with the same type are expected to use the same field names and meanings.                                                     |
| `CertificateSerialNumber` | Base64 string          | 32 bytes                                                | Uniquely identifies a certificate from a certifier.                                                                                                                         |
| `PublicKey`               | Hex string             | 33 bytes                                                | Compressed secp256k1 public key.                                                                                                                                            |
| `RevocationOutpoint`      | `<txid>.<vout>` string | 32-byte txid followed by VarInt vout                    | Identifies the UTXO whose spend revokes the certificate. The disabled sentinel is `0000000000000000000000000000000000000000000000000000000000000000.0`.                     |
| `Signature`               | Hex string             | DER-encoded ECDSA bytes                                 | Certifier signature over the core certificate binary preimage.                                                                                                              |
| `CertificateFieldName`    | UTF-8 string           | VarInt length followed by UTF-8 bytes                   | 1 to 50 UTF-8 bytes. Field names and their signed presentation order MUST be preserved as described below; printable ASCII alone does not establish interoperable ordering. |
| `CertificateFieldValue`   | Base64 string          | UTF-8 bytes of the Base64 string in `CertificateBinary` | Encrypted field value, encoded as Base64 for JSON and signed as that Base64 string.                                                                                         |
| `KeyringValue`            | Base64 string          | Base64-decoded bytes in keyring-map binary encodings    | BRC-2 encrypted field revelation key.                                                                                                                                       |

## Core Certificate JSON

A core certificate is a JSON object with exactly these signed members:

| Field                | Type                                                     | Description                  |
| -------------------- | -------------------------------------------------------- | ---------------------------- |
| `type`               | `CertificateTypeID`                                      | Certificate type identifier. |
| `serialNumber`       | `CertificateSerialNumber`                                | Certificate serial number.   |
| `subject`            | `PublicKey`                                              | Subject identity key.        |
| `certifier`          | `PublicKey`                                              | Certifier identity key.      |
| `revocationOutpoint` | `RevocationOutpoint`                                     | Revocation UTXO reference.   |
| `fields`             | map of `CertificateFieldName` to `CertificateFieldValue` | Encrypted certified fields.  |
| `signature`          | `Signature`                                              | Certifier signature.         |

Example:

```json
{
  "type": "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=",
  "serialNumber": "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI=",
  "subject": "024d4b6cd1361032f49d6c5cb7198fdd0458d4fd5f2d0f418da24ff2b63243a6f7",
  "certifier": "03531fe6068134503d846f476d6b2e3c000d70bb7c3937c8d537ef7d24c7d9e6c8",
  "revocationOutpoint": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef.1",
  "fields": {
    "email": "uS49rSc3jHRjmE3+/sT1Kf12p2vISiVfDX4SzsqKXWQJdVfuZJcgxjp34MBzEP9PIzK+8j7JqUs=",
    "name": "CSDUXeL3aMCSdWGMZmkAPq4iH0K2FfCUvYZZF/7l4hRLIgSJg+gMojGZrXJ+6qKQ"
  },
  "signature": "304402201f0f2c2d86ad4c2271170cf967f7a9d6106d81e5b7d273decae34d284fcfced9022023cccf38074113a7e8620d9b97b860c7cb7b54805af343c03d3f44ce12da55b8"
}
```

The `signature` member MUST NOT be included when computing the signature preimage. Keyrings and decrypted fields MUST NOT be included in the core certificate signature.

There is no `validationKey` field in this specification. Implementations MUST verify certificates using the certifier identity key and the BRC-100 signature derivation described below.

## Certificate Binary Format

`CertificateBinary` is the binary form of the core certificate and the signature preimage source. Its byte sequence, including the order and encoding of field entries, is part of the signed representation. It is serialized in this exact order:

| Order | Field                     | Encoding                                                                                                                              |
| ----- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| 1     | `type`                    | 32 bytes, Base64-decoded from JSON.                                                                                                   |
| 2     | `serialNumber`            | 32 bytes, Base64-decoded from JSON.                                                                                                   |
| 3     | `subject`                 | 33 bytes, hex-decoded from JSON.                                                                                                      |
| 4     | `certifier`               | 33 bytes, hex-decoded from JSON.                                                                                                      |
| 5     | `revocationOutpoint.txid` | 32 bytes, hex-decoded txid.                                                                                                           |
| 6     | `revocationOutpoint.vout` | VarInt output index.                                                                                                                  |
| 7     | `fields.count`            | VarInt number of fields.                                                                                                              |
| 8     | each field                | Field entries ordered as described below, each as `VarInt nameLength`, `name UTF-8 bytes`, `VarInt valueLength`, `value UTF-8 bytes`. |
| 9     | `signature`               | DER signature bytes, only when serializing with the signature included.                                                               |

### Field Encoding and Historical Ordering

`nameLength` and `valueLength` count the UTF-8 **bytes** that follow each prefix, not Unicode characters or a language's string length. Field values in `CertificateBinary` are the UTF-8 bytes of the Base64 string, not the Base64-decoded ciphertext bytes. Serializers and verifiers MUST preserve the field-name strings and Base64 text used in the signed representation. They MUST NOT apply Unicode normalization, case folding, locale conversion, or Base64 decoding and re-encoding to an existing signed field while reconstructing its preimage.

The historical TypeScript reference serializer orders `Object.keys(fields)` using the stable comparison `a.localeCompare(b)` with no explicit locale or options. Distinct strings that compare equal retain their order in that key list. This is host-dependent collation, not UTF-8 byte ordering or ECMAScript's default string sort. Printable ASCII does not remove the difference: case and punctuation can sort differently under those comparators. Unicode collation can also vary with locale and runtime collation data.

For compatibility with a certificate signed by that serializer, an implementation reconstructing the preimage MUST reproduce the issuer's field order and exact encoded field text. It MUST NOT substitute another comparator and assume that the resulting byte sequence is equivalent. This specification does not designate a single locale, runtime version, or cross-language comparator as a universally canonical replacement for historical ordering. Implementations exchanging JSON-only certificates SHOULD document their compatible serialization environment, field-name schema, and complete preimage test vectors; JSON alone carries no ordering-profile identifier. Unsigned profile metadata can help identify an environment, but cannot change or authenticate historical signed bytes.

A binary transport or adapter SHOULD retain the original unsigned prefix and signature bytes so verification does not depend on local reordering. A reader verifying retained bytes MUST parse and validate the same bytes that it authenticates and bind every accepted certificate value to that parsed representation. Malformed UTF-8, duplicate field names, invalid length prefixes, and malformed signatures MUST NOT be made acceptable by retaining bytes. Retaining bytes is not a claim that the current TypeScript `Certificate.fromBinary(...).verify()` path performs this operation: that path parses fields and then calls the local serializer again.

Because the raw signature is the final field and is not length-prefixed in `CertificateBinary`, any enclosing binary protocol that appends extension data after a certificate MUST length-prefix the complete `CertificateBinary` first.

## Signature Creation and Verification

The signature preimage is the exact unsigned prefix of the signed `CertificateBinary`, equivalent to the issuer's serialization with `includeSignature = false`. A verifier MAY verify that retained prefix directly, subject to the parsing and value-binding requirements above. A verifier reconstructing the prefix from structured data MUST use a compatible serialization that reproduces the signed byte sequence. The preimage MUST be hashed with SHA-256 by the BRC-100 signature method before ECDSA signing.

The certifier signs using:

| BRC-100 signature parameter | Value                                                                                                                                  |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `protocolID`                | `[2, "certificate signature"]`                                                                                                         |
| `keyID`                     | `<type> <serialNumber>` using the JSON Base64 strings separated by one U+0020 space                                                    |
| `counterparty`              | Publicly verifiable signature semantics. In current `ts-sdk`, this is produced by omitting `counterparty`, which defaults to `anyone`. |
| `data`                      | The preimage bytes from `CertificateBinary(false)`.                                                                                    |

A verifier verifies using:

| BRC-100 verification parameter | Value                                                                    |
| ------------------------------ | ------------------------------------------------------------------------ |
| `protocolID`                   | `[2, "certificate signature"]`                                           |
| `keyID`                        | `<type> <serialNumber>`                                                  |
| `counterparty`                 | The certificate `certifier` public key.                                  |
| `data`                         | The same preimage bytes from `CertificateBinary(false)`.                 |
| `signature`                    | DER signature bytes decoded from the certificate `signature` hex string. |

Top-level JSON member ordering is not itself signed. However, field enumeration order can affect historical stable collation when distinct names compare equal, as described above; converting through a JSON map MUST NOT be assumed to preserve the preimage. Implementations MUST NOT use stable JSON stringification as the certificate signature preimage.

## Field Encryption

Each certificate field value is encrypted independently:

1. Generate a random 32-byte field revelation key `K_f`.
2. UTF-8 encode the plaintext field value.
3. Encrypt the plaintext with AES-256-GCM using `K_f`.
4. Encode the encrypted field value as `Base64(IV || ciphertext || tag)`.

The IV MUST be 32 bytes. The authentication tag MUST be 16 bytes. No additional authenticated data is used by the current reference implementation.

The certifier signs only the encrypted `fields` map. Plaintext field values, field revelation keys, keyrings, and decrypted field caches MUST NOT be signed as part of the core certificate.

## Keyring Encryption

A keyring value is a BRC-2/BRC-100 encrypted field revelation key. The plaintext is the raw 32-byte `K_f`. The ciphertext is encoded as `Base64(IV || ciphertext || tag)` where the IV and tag follow BRC-2 encryption behavior.

All certificate keyring encryption uses:

| BRC-100 encryption parameter | Master keyring                        | Verifier keyring                                    |
| ---------------------------- | ------------------------------------- | --------------------------------------------------- |
| `protocolID`                 | `[2, "certificate field encryption"]` | `[2, "certificate field encryption"]`               |
| `keyID`                      | `<fieldName>`                         | `<serialNumber> <fieldName>` using one U+0020 space |
| `plaintext`                  | Raw 32-byte field revelation key      | Raw 32-byte field revelation key                    |

For a master keyring, the encrypting party sets `counterparty` to the other party that must be able to decrypt the keyring value. In direct or certifier-issued flows, this is normally the certifier when the subject creates the encrypted fields, or the subject when the certifier creates the encrypted fields.

For a verifier keyring, the subject decrypts the applicable master keyring entries and re-encrypts the raw field revelation keys with `counterparty = verifier`. The verifier decrypts those keyring entries with `counterparty = subject`.

## Master Certificates

A master certificate is a core certificate plus a complete keyring that can reveal every field in `fields`.

Canonical JSON extension:

```json
{
  "type": "...",
  "serialNumber": "...",
  "subject": "...",
  "certifier": "...",
  "revocationOutpoint": "...",
  "fields": {
    "name": "..."
  },
  "signature": "...",
  "masterKeyring": {
    "name": "..."
  }
}
```

The `masterKeyring` member MUST contain exactly one non-empty keyring value for every field in `fields`. SDK and wallet API contexts MAY name the same data `keyringForSubject` or `keyring`; those names are aliases for the master keyring in that context and MUST NOT alter signature semantics.

Before storing or accepting a master certificate, a wallet SHOULD verify:

1. The core certificate signature is valid.
2. The master keyring contains an entry for every field.
3. Every master keyring entry decrypts to a field revelation key that decrypts its corresponding encrypted field value.

## Verifiable Certificates

A verifiable certificate is a core certificate plus a verifier-specific keyring for zero or more selected fields.

Canonical JSON extension:

```json
{
  "type": "...",
  "serialNumber": "...",
  "subject": "...",
  "certifier": "...",
  "revocationOutpoint": "...",
  "fields": {
    "email": "...",
    "name": "...",
    "organization": "..."
  },
  "signature": "...",
  "keyring": {
    "email": "...",
    "name": "..."
  }
}
```

The `keyring` member MUST contain only fields present in `fields`. It MAY be empty or omitted when no fields are revealed. The verifier MUST verify the core certificate signature before relying on any decrypted field. The verifier MUST decrypt only fields for which keyring entries are present.

The BRC-100 `proveCertificate` result returns this verifier keyring as `keyringForVerifier`; a transmitted verifiable certificate uses `keyring`.

## Extension Binary Encodings

The raw `CertificateBinary` format is the only signed binary format. Extension binary formats are unsigned envelopes for carrying keyrings next to a length-prefixed core certificate.

`KeyringMapBinary`:

| Order | Field        | Encoding                                                                                                    |
| ----- | ------------ | ----------------------------------------------------------------------------------------------------------- |
| 1     | `entryCount` | VarInt.                                                                                                     |
| 2     | each entry   | `VarInt fieldNameLength`, field name UTF-8 bytes, `VarInt valueLength`, Base64-decoded keyring value bytes. |

`CertificateWithKeyringBinary`:

| Order | Field               | Encoding                                                               |
| ----- | ------------------- | ---------------------------------------------------------------------- |
| 1     | `certificateLength` | VarInt length of the complete `CertificateBinary` including signature. |
| 2     | `certificate`       | `CertificateBinary`.                                                   |
| 3     | `keyring`           | `KeyringMapBinary`.                                                    |

The same envelope is used for master certificates and verifiable certificates; the interpretation of the keyring is determined by context. When the keyring is absent, protocols SHOULD transmit the raw `CertificateBinary` rather than an empty envelope.

BRC-100 wallet-wire methods use method-specific envelopes around the same primitives. For example, `proveCertificate` submits a core certificate structure and receives a `KeyringMapBinary`; `listCertificates` length-prefixes each certificate and may append a keyring flag, keyring map, and verifier value. Those wallet-wire envelopes do not change the BRC-52 core certificate format.

## Certificate Acquisition and Revelation

### Direct Acquisition

In direct acquisition, a wallet receives a signed core certificate and a master keyring from a certifier or other keyring revealer. The wallet MUST set or confirm `subject` as its own identity key before storage. The wallet MUST verify the signature and confirm that the master keyring decrypts the fields before storing the certificate.

### Issuance Acquisition

In issuance acquisition, the subject prepares encrypted fields and a master keyring for the certifier, then sends the encrypted fields to the certifier for signing. The certifier returns a signed core certificate. The subject stores the returned certificate with the master keyring it generated, after verifying that the returned type, subject, certifier, fields, serial number derivation, revocation outpoint, and signature are acceptable for the issuance protocol being used.

### Selective Revelation

To reveal fields to a verifier:

1. The subject locates the stored master certificate.
2. The subject verifies the requested field names are a subset of the certificate fields.
3. The subject decrypts each requested master keyring value to recover `K_f`.
4. The subject re-encrypts each `K_f` for the verifier using the verifier keyring parameters above.
5. The subject returns the verifier keyring, either as a `keyringForVerifier` result or embedded in a verifiable certificate as `keyring`.

## Revocation

The `revocationOutpoint` points to a UTXO controlled according to the certifier's revocation policy. If that UTXO has been spent, the certificate MUST be treated as revoked. If the disabled sentinel `0000000000000000000000000000000000000000000000000000000000000000.0` is used, UTXO-based revocation is disabled and verifiers MUST rely on the policy for that certificate type.

Certifiers SHOULD publish clear rules for revocation monitoring, reissuance, and key compromise handling. If a certifier identity key is compromised, the certifier SHOULD revoke affected certificates and reissue under a new certifier identity key.

## Implementation Basis

This revision is grounded in the reference behavior of the BSV SDK and Wallet Toolbox certificate implementations, including:

* `Certificate`, `MasterCertificate`, and `VerifiableCertificate` behavior in `bsv-blockchain/ts-sdk`.
* Certificate lifecycle, wallet storage, `acquireCertificate`, `listCertificates`, and `proveCertificate` behavior in `bsv-blockchain/wallet-toolbox`.

## Compatibility and Serialization Checks

This clarification preserves the existing TypeScript signature and field encodings. It does not change signed certificates to a new bytewise field order or require a new signature. Existing certificates cannot be normalized to a different field order without changing the signed preimage. When structured storage has discarded the original bytes, successful verification of a known compatible serialization is required before exporting those bytes as the signed representation. If the original ordering cannot be recovered, an implementation MUST report that it cannot verify the certificate; it MUST NOT represent a silently reordered certificate as verified.

The Go reference serializer currently uses `sort.Strings`, which can differ from TypeScript locale collation. This is an implementation difference, not an additional equivalent canonical ordering. Compatibility requires identical preimages and the signature derivation defined here, not merely similar parsed objects. This revision does not endorse unrelated incompatible implementation behavior.

Conformance checks SHOULD include:

1. Confirm that `é` (U+00E9) has a name length of 2 and `é` (U+0065 U+0301) has a name length of 3. They are distinct signed field names and MUST NOT be normalized into one another.
2. Confirm that the field entry for name `é` and value `AQ==` is `02 c3 a9 04 41 51 3d 3d`; the value length is 4, not the length of its decoded ciphertext.
3. Record the reference collation environment and verify complete signed preimage vectors containing mixed case, punctuation, and non-ASCII field names. Compare actual bytes rather than assuming that a comparator's name implies compatibility.
4. Confirm that a reader either verifies the preserved unsigned prefix with exact parsed-value binding or reproduces that prefix before verifying. A field reordering that changes the preimage MUST fail verification under the unchanged signature.

## Revision Notes

* 2026-09-30: Clarified UTF-8 byte lengths, historical TypeScript locale-dependent ordering, and preservation of the signed representation. Removed the inaccurate assertion that printable ASCII field names necessarily sort identically across implementations. Added implementation-pinned evidence and compatibility checks without assigning a new serialization format.

## References

* [TypeScript reference `Certificate` at commit `3e41d6a220783b268b6240ae654f27628c4af557`](https://github.com/bsv-blockchain/ts-stack/blob/3e41d6a220783b268b6240ae654f27628c4af557/packages/sdk/src/auth/certificates/Certificate.ts): `toBinary`, `fromBinary`, `verify`, and `sign`.
* [TypeScript UTF-8 primitives at the same commit](https://github.com/bsv-blockchain/ts-stack/blob/3e41d6a220783b268b6240ae654f27628c4af557/packages/sdk/src/primitives/utils.ts) and [UTF-8 encoder](https://github.com/bsv-blockchain/ts-stack/blob/3e41d6a220783b268b6240ae654f27628c4af557/packages/sdk/src/primitives/UTF8.ts).
* [Go reference serializer at commit `f20deedaf9f8f8807538c4623db46c0bdc2472cf`](https://github.com/bsv-blockchain/go-sdk/blob/f20deedaf9f8f8807538c4623db46c0bdc2472cf/wallet/serializer/certificate.go).
* [ECMA-402, `String.prototype.localeCompare`](https://tc39.es/ecma402/#sec-string.prototype.localecompare) and [implementation dependencies](https://tc39.es/ecma402/#sec-implementation-dependencies).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://bsv.brc.dev/peer-to-peer/0052.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
