> For the complete documentation index, see [llms.txt](https://hub.bsvblockchain.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hub.bsvblockchain.org/brc/payments/0175.md).

# 1Color Offline Peer-to-Peer Payments

Deggen (<d.kellenschwiler@bsvassociation.org>)

## Abstract

This BRC specifies how one wallet pays [1Color (BRC-162)](/brc/tokens/0162.md) tokens to another wallet when either party, or both, may be offline. The payer hands the payee one **payment bundle**: a signed transaction, the data the payee needs to recognize its output, and enough evidence to show that every token the payer spends traces back to outputs an overlay has already admitted. The payee checks the bundle without any network access, credits the payment or holds it until missing evidence arrives, and settles it with the overlay later.

The evidence is an **admission attestation**: an overlay operator's signature over the outputs it admitted. The payee walks back through the transaction graph until every token input ends at an attested output, or at an output the payee has verified itself. It trusts an attestation only when the signer's identity key is one of its own trust anchors.

Offline acceptance carries counterparty risk: the payer could spend the same input twice before the payee settles. This BRC states that risk and, for regulated assets, how it is contained. The overlay records the owner of every admitted output, so a double-spent outpoint identifies the identity key that spent it, even when the payment used sender blinding. Under that asset's identity registration, the key identifies a person.

The bundle has one binary encoding. Bindings are given for a nearby session (QR pairing, sealed frame, air-gap QR) and for a [BRC-33](/brc/peer-to-peer/0033.md) message box.

## Motivation

A token payment today is accepted when its overlay admits it. That needs a network connection at the moment of payment. Many real payments happen without one: in a shop with poor signal, between two phones on a train, at a market stall. A stablecoin that only works online is a weaker substitute for cash.

The rules needed to accept a payment offline safely are subtle. The payee must know which ancestors to check, what signature stands in for the overlay, whose signature to believe, what to do when settlement later fails, and why it is reasonable to take the risk at all. Until now these rules existed only in one wallet's source code. This document states them so that other wallets, overlays and issuers can interoperate.

[BRC-207](/brc/wallet/0207.md) requires a current overlay answer before a wallet spends or accepts a token. This BRC defines the **deferred admission** policy that relaxes that requirement under the conditions below. A wallet chooses whether to offer it. It applies to any 1Color asset and needs no declaration by the issuer.

## Relationship to other documents

| Concern                                               | Document                                                                     |
| ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| Token encoding, asset ID, supply rules                | [BRC-162](/brc/tokens/0162.md)                                               |
| Wallet module, key namespace, baskets, overlay topics | [BRC-207](/brc/wallet/0207.md)                                               |
| Key derivation and invoice numbers                    | [BRC-42](/brc/key-derivation/0042.md), [BRC-43](/brc/key-derivation/0043.md) |
| Specific key linkage disclosure                       | [BRC-69](/brc/key-derivation/0069.md), [BRC-72](/brc/key-derivation/0072.md) |
| Transaction envelope                                  | [BRC-62](/brc/transactions/0062.md), [BRC-233](/brc/transactions/0233.md)    |
| Token lineage proofs (walk to deploy)                 | [BRC-176](/brc/tokens/0176.md)                                               |
| Overlay submission                                    | [BRC-22](/brc/overlays/0022.md)                                              |
| Trust anchors                                         | [BRC-189](/brc/wallet/0189.md)                                               |
| Expiry of unsent actions                              | [BRC-177](/brc/wallet/0177.md)                                               |
| Air-gap QR transport                                  | [BRC-141](/brc/peer-to-peer/0141.md)                                         |
| Message box relay, handles                            | [BRC-33](/brc/peer-to-peer/0033.md), [BRC-169](/brc/peer-to-peer/0169.md)    |
| Ephemeral sender keys                                 | [BRC-228](/brc/payments/0228.md)                                             |

BRC-176 proves lineage all the way back to a deploy. This BRC stops the walk at the first attested output. That keeps a bundle small enough for a QR code, at the cost of trusting the attesting overlay for everything older.

MUST, MUST NOT, SHOULD and MAY express requirements for conforming implementations.

## Roles

| Role               | Does                                                               | Is trusted for                                                    |
| ------------------ | ------------------------------------------------------------------ | ----------------------------------------------------------------- |
| Payer              | Builds, signs and hands over the bundle                            | Nothing. Every claim is checked.                                  |
| Payee              | Checks the bundle, credits it, settles it                          | Its own trust choices                                             |
| Overlay operator   | Admits transactions to `tm_color_<assetId>` and signs attestations | Having admitted the attested outputs, if the payee trusts its key |
| Identity registrar | For regulated assets, binds identity keys to real-world persons    | Identity of a key's owner, outside this protocol                  |

One organization MAY hold several roles. An issuer commonly runs the overlay and the registrar.

## Admission attestation

An attestation is an overlay operator's statement: "the topic `tm_color_<assetId>` admitted these outputs of this transaction."

### Message

```
1color-admit:v1:<topic>:<txid>:<outputs>
```

* `topic` is `tm_color_<assetId>` per BRC-207, using the canonical asset ID `<64 lowercase hex>_<decimal vout>`.
* `txid` is 64 lowercase hex characters, in display order.
* `outputs` is the admitted output indices as decimal integers without leading zeroes, unique, ascending and joined by `,`. It MUST NOT be empty.

The topic is part of the message so an attestation for one asset cannot be replayed as evidence for another.

### Signature

The signer signs with the [BRC-42](/brc/key-derivation/0042.md) child of its identity key for protocol `[2, "color admission attestation"]`, key ID `"1"` and counterparty `"anyone"`. The invoice is `2-color admission attestation-1`. This is what BRC-100 `createSignature({data: UTF-8(message), protocolID, keyID: "1", counterparty: "anyone"})` does: it computes `e = SHA-256(UTF-8(message))` once and signs `e` with ECDSA over secp256k1. The dedicated protocol keeps attestation signatures apart from every other use of the signer's keys.

A verifier derives the signer's child publicly, using the anyone private key `1` and the same invoice, or calls `verifySignature` from an anyone wallet with the same tuple and `counterparty` set to the signer's identity key. It MUST NOT verify against the bare identity key. A signature made with the bare identity key is not a valid attestation.

Signers SHOULD use RFC 6979 deterministic nonces, so re-signing the same message gives the same bytes and settlement retries are idempotent. The signature is DER encoded. Verifiers MUST accept any valid `S` value and MUST NOT require low-S.

An overlay MUST sign only outputs its topic has admitted. It returns the attestation for each topic in its BRC-22 submission response as `admissionSignature` (lowercase DER hex) and `admissionIdentityKey` (the signer's identity key, compressed, 66 hex), next to that topic's `outputsToAdmit`.

### Meaning and limits

An attestation lists the **complete** set of outputs of that transaction the topic admitted, as the signer knew it at signing time. An overlay MUST NOT sign a partial set. So an output missing from an attestation by a signer the payee accepts was not admitted by that signer, and the walk-back treats it as refused. Local validation cannot see an overlay's policy refusals, such as a frozen input, a sanctioned identity or a missing KYC registration; the complete set is how they reach an offline payee.

An attestation proves admission at signing time. It does **not** prove the output is still unspent. It is a probabilistic reduction of risk, not a guarantee, so it carries no timestamp and no expiry. That gap is the counterparty risk discussed below.

### Trust

A verifier MUST accept an attestation only when the signer key is one of its trust anchors under [BRC-189](/brc/wallet/0189.md), and the signature verifies against **that** anchor's derived child. A key named inside a bundle is a hint for lookup. It is never a reason to trust. Nothing in the asset's deploy names a signer.

Wallet builds normally ship with the issuers' attesting keys already trusted. A user MAY add or remove a key at any time, for example one published on an asset's website. Removing a key affects only future checks. Rotation and revocation of an issuer's attesting key belong to the issuer's authority chain and are outside this BRC.

## Payment bundle

### Encoding

All integers marked VarInt use Bitcoin CompactSize encoding in its minimal form. A non-minimal VarInt MUST fail. `str` is a VarInt byte length followed by strict UTF-8. `bytes` is a VarInt length followed by raw bytes. A `txid` field is 32 bytes in display order: the bytes of the hex string as written. A decoder MUST reject trailing bytes.

```
u8      version            = 0x01
33B     senderKey
VarInt  outputIndex
str     derivationPrefix
str     derivationSuffix
str     assetId
VarInt  nSubmissions
        nSubmissions × { 32B txid ; bytes offChainValues }
VarInt  nAttestations
        nAttestations × { 32B txid ; VarInt nOutputs ; nOutputs × VarInt output ;
                          bytes signature ; 33B signerKey }
str     note
bytes   transaction
```

### Why each field is sent

| Field                                  | Why the payee needs it                                                                                                                                                                                                                                                                       |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`                              | Lets a decoder refuse a format it does not implement.                                                                                                                                                                                                                                        |
| `senderKey`                            | The counterparty for deriving the payee's output key under BRC-42. It is the blinded key `A′` for a blinded payment, or the payer's identity key `A` otherwise. The payee treats both the same way.                                                                                          |
| `outputIndex`                          | Which output of the tip pays the payee. Output order is randomized, so the payee cannot guess it.                                                                                                                                                                                            |
| `derivationPrefix`, `derivationSuffix` | The remittance strings that select the payee's key in the BRC-207 namespace. On the nearby rail the payee chose them, which binds the bundle to one session.                                                                                                                                 |
| `assetId`                              | Which asset is being paid. It fixes the topic, the attestation message and the per-asset basket.                                                                                                                                                                                             |
| submissions                            | For the tip and every unattested token ancestor, the exact off-chain values the overlay needs to admit that transaction. The payee must be able to settle without the payer, so it carries what the payer would have sent. For an asset without ownership disclosure the value MAY be empty. |
| attestations                           | Where the walk-back stops. Each entry lets the payee confirm, offline, that the overlay already admitted the named outputs, and that it admitted no others.                                                                                                                                  |
| `note`                                 | Optional message from payer to payee. Display only. Empty means absent.                                                                                                                                                                                                                      |
| `transaction`                          | A [BRC-233](/brc/transactions/0233.md) Subject BEEF whose subject is the tip. It carries the bodies the payee needs to validate scripts, Bitcoin evidence and conservation, to read the asset's deploy, and to settle. See the structural rules.                                             |

There is deliberately no amount field: the amount is read from the payee's output script, so the bundle cannot claim a different one. There is also no overlay URL and no trusted key: the payee uses its own configuration for both, so a payer cannot steer it to a server or signer of the payer's choosing.

### Structural rules

* `senderKey` and each `signerKey` MUST be valid compressed secp256k1 points. `signerKey` is the signer's identity key, not its derived child.
* `assetId` MUST be canonical as defined in BRC-162.
* Submission txids MUST be unique. Attestations MUST be unique by `(txid, signerKey)`; several signers MAY attest one transaction. No txid appears in both the submissions and the attestations.
* Attestation outputs MUST be ascending and unique, and the list MUST NOT be empty.
* `derivationPrefix` and `derivationSuffix` MUST satisfy BRC-207's remittance rules: nonempty strict UTF-8 without whitespace. The resulting protocol name MUST fit BRC-43's 280-character bound.
* `transaction` MUST parse as a BRC-233 Subject BEEF whose subject is the tip. Like a [BRC-176](/brc/tokens/0176.md) packet, it MUST NOT be validated, stripped or round-tripped as BRC-95 Atomic BEEF: BRC-95 handling may drop the ancestor bodies the walk-back needs.
* `transaction` MUST contain the full body of the tip, of every transaction the walk-back expands, and of the source of every input of those transactions, including attested parents and fee inputs, so every input script can be validated. It MUST contain Bitcoin evidence ([BRC-62](/brc/transactions/0062.md) merkle paths or unmined ancestors) for every input.
* `transaction` MUST contain the deploy transaction body, unless the payee already holds it. The deploy is authenticated by its bytes hashing to the txid in `assetId`. The payee reads the deploy's BRC-162 payload for display fields and for any required profile, such as issuer controls.

A bundle that breaks any rule fails as `decode_failed`.

## Walk-back

The walk-back decides whether every token in the payment traces to verified outputs, and which transactions the payee must settle. It runs without network access.

```
function walk(tx):                       // tx starts as the tip
    if tx.txid is on the stack: fail "shape"         // malformed bag
    for each input i of tx:
        parentId, vout = i.sourceTxid, i.sourceOutputIndex
        parent = body of parentId in transaction
        if parent is absent: fail "uncovered_ancestor"          // rule B
        if parent.outputs[vout] is not a token of assetId: continue   // rule K
        if anchored(parentId, vout): continue        // bottom of this branch
        if refused(parentId, vout): fail "uncovered_ancestor"   // rule A
        walk(parent)
        mustSubmit.add(parentId)
    return

anchored(txid, vout) =
    attested(txid, vout)
    or (the asset declares no issuer-controls profile
        and the payee has itself verified that output to the deploy)

attested(txid, vout) =
    an attestation for txid exists whose signerKey is a trust anchor,
    whose signature verifies for topic tm_color_<assetId>, and whose outputs include vout

refused(txid, vout) =
    an attestation for txid by a trust anchor verifies, and its outputs omit vout
```

The result is `mustSubmit` plus the tip, ordered so every parent comes before its children. A transaction reached through several inputs is walked once.

Rules A, B and K, and why they exist:

* **A. Admitted, but not this output.** An attestation lists the complete admitted set, so an omitted output was refused by that overlay, for example a phantom coin from an over-output transaction, or an output refused on policy grounds. The walk MUST NOT search further back to justify it.
* **B. Missing body.** Every parent needs its body, even an attested one, because the child's input script must be validated against the parent's output. A mined parent is **not** treated as admitted: mined is not admitted.
* **K. Non-token inputs.** Inputs that do not carry this asset, such as fee funding, are neither walked nor counted for token lineage. Their scripts and Bitcoin evidence are still validated below.

**Self-verified anchors.** A payee MAY end a branch at an output it has itself verified back to the deploy, for example under a complete [BRC-176](/brc/tokens/0176.md) lineage check. This lets wallets that do not rely on overlays share assets with wallets that do. It applies only to assets whose deploy declares no required processing profile that depends on overlay state, such as issuer controls. For an asset under issuer controls only an attestation can anchor, because only the overlay sees freezes and registration status.

Every txid in `mustSubmit`, and the tip, MUST have a submission entry. Otherwise the bundle fails as `not_covered`. A wallet MAY cap walk depth or bundle size by policy; exceeding a cap fails as `limit_exceeded`.

## Payee acceptance

Acceptance has three outcomes:

| Outcome      | Meaning                                                                       | What the payee keeps                                               |
| ------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| **credited** | Every check passed.                                                           | The bundle, and the output in its balance with `color_offline`     |
| **held**     | Every check the payee can make passed, but some evidence is not available yet | The bundle, durably, as pending. Nothing is credited or spendable. |
| **declined** | A check failed                                                                | Nothing                                                            |

A payment is held, not declined, when the only failures are temporary:

* a merkle path names a block above the payee's verified header tip;
* a source transaction body is missing but the payee expects to obtain it later.

A held payment is re-checked on a schedule and whenever evidence arrives. It then becomes credited or declined. A payee MUST cap held payments per sender and in total. When a cap is reached, a new payment is declined as `limit_exceeded`, never silently dropped.

The payee MUST run these checks in order. A hard failure stops the checks and declines the payment with the ack code shown. A temporary condition is recorded and checking continues. If no hard failure occurs but a temporary condition remains, the payment is held.

1. **Decode.** The bundle decodes under the structural rules. Else `decode_failed`.
2. **Output.** `outputIndex` names a tip output that is a BRC-162 value output of `assetId` with a P2PKH remainder. Else `invalid_tx`.
3. **Ownership.** The payee computes its key with BRC-100 `getPublicKey`. The arguments are `protocolID` `[2, "p color <assetTag> <prefixTag> <suffixTag>"]` and `keyID` `"color"` per BRC-207, with `counterparty: senderKey` and `forSelf: true`. The HASH160 of that key MUST equal the output's public key hash. Else `session_mismatch`. This proves the payee alone can spend the output.
4. **Scripts.** Every input of the tip and of each `mustSubmit` transaction MUST pass consensus script validation against its source output. The tip MUST be consensus-final. Else `invalid_tx`.
5. **Bitcoin evidence.** Each merkle path is checked against the payee's **own** header chain, never against headers carried in the bundle. Each check gives one of three results:
   * **valid**: the path proves inclusion in a block the payee holds;
   * **invalid**: the path is malformed, or contradicts a header the payee holds. The bundle fails as `invalid_tx`;
   * **unknown**: the path names a block above the payee's verified tip. The payment is held.
6. **Token rules.** The tip and each `mustSubmit` transaction MUST satisfy BRC-162 conservation and authority rules for `assetId`, with all inputs counted from walked or anchored sources. Else `invalid_tx`.
7. **Walk-back.** It succeeds. Else `not_covered`.
8. **Session or request.** On the nearby rail the prefix, suffix, asset and any requested amount equal the session's. Else `session_mismatch`. A session already paid fails as `already_paid`, here or atomically at step 10.
9. **Policy.** The amount and depth fit the payee's deferred-admission limits, and held caps are not exceeded. Else `limit_exceeded`.
10. **Save.** The payee durably stores the bundle and marks the session spent, in one atomic step. For a credited payment, the same commit records the credit, or a pending application of it that can be completed idempotently. Else `save_failed`.
11. **Ack.** The payee sends its ack, then exposes the output with `color_offline`, or shows the payment as held. A crash before or after the ack cannot lose or duplicate a credit. No ack asserts Bitcoin confirmation or that the inputs are still unspent.

## Settlement

Settlement turns an offline credit into an admitted one.

**Who submits.** The payee submits. Once the payee has acked the payment as credited, the payer MAY also submit. After a held ack the payer waits for the final outcome and does not submit. Submission is idempotent, so a duplicate does no harm. If the payee declines, **neither party submits** the transaction. The payer either resends a corrected payment or cancels. A payee that declined MUST NOT submit what it declined. With no ack channel, as on the QR fallback, the payer MUST NOT submit until it learns of acceptance.

**Online payments.** A payee that is online when it receives a bundle settles immediately, using the same steps. This also works when payer and payee trust different overlays, because the payee submits to its own.

Steps:

1. Submit each `mustSubmit` transaction, then the tip, in order. Each goes to the settling party's configured provider for `tm_color_<assetId>` with its submission entry's off-chain values.
2. Accept an admission only when it carries an attestation from a trust anchor covering the expected outputs. An unsigned or unverifiable answer is a retryable failure, never an admission.
3. Store each attestation. It becomes evidence for later bundles.
4. Broadcast only after the overlay has admitted the transaction. Broadcasting the tip's BEEF also broadcasts its unmined ancestors. If a transaction were mined before admission and the overlay then refused it, its token inputs would be destroyed on-chain.
5. When the tip is admitted, remove the `color_offline` tag.

Outcomes:

| Outcome                                                    | Payee action                                                                                              |
| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Retryable (unavailable, rate-limited, unverifiable answer) | Keep state and retry with backoff.                                                                        |
| Final refusal of the tip or an ancestor                    | Mark it refused and its descendants orphaned. Remove the credit and correct the balance. Keep the bundle. |
| Conflict: an input already spent by another transaction    | As for a final refusal. Also record the competing txid the overlay reports. Keep the bundle as evidence.  |

A wallet SHOULD tell the user when settlement has not finished within its stale threshold. A threshold of three days is suggested.

**Payer exposure.** Once a payer has released signed bytes, it MUST keep the spent inputs reserved and the exposure recorded. That holds after a negative ack too, because the payee still holds bytes that could be submitted. The reservation ends only when the tip is admitted, a conflicting spend is established, or the payer cancels. To cancel, the payer spends the inputs back to itself once online; it MUST tell the user that the cancel races any copy of the original. A wallet SHOULD offer that cancel explicitly after a decline.

## Deferred admission policy

This section defines the BRC-207 wallet policy that makes offline payment possible. A wallet MAY offer it. When enabled, it applies to every 1Color asset. No declaration by the issuer is needed or possible: the risk falls on the holder who accepts it, and issuer supply is never affected. An asset that declares an issuer-controls profile still has that profile's rules applied at settlement.

* **Accepting.** An output accepted under this BRC is held with the BRC-207 state tag `color_state_available` and the additional wallet-authored tag `color_offline`. It counts toward the asset's token balance. Applications cannot set or remove `color_offline`. This extends BRC-207, which otherwise reserves `color_state_available` for admitted outputs.
* **Held payments.** A held payment contributes nothing to the balance and cannot be spent. Wallets SHOULD show it as an incoming payment pending verification.
* **Spending offline.** A `color_offline` output MAY be spent in a new bundle. The payer forwards the evidence: its own bundle's submission entries and attestations for every still-unattested ancestor. A payment whose Bitcoin evidence is unknown is held, not credited, so unverifiable evidence never travels onward.
* **Spending online.** Before an online spend of a `color_offline` output releases a signature, the wallet MUST settle the transaction that created the output and its unattested ancestors. If any is refused, the spend fails before broadcast.
* **Limits.** The wallet sets per-asset amount caps, maximum walk depth, maximum age, held-payment caps and accepted counterparties. The user consents to the policy when enabling it, and that consent authorizes later settlement.
* **Lifecycle promises.** A wallet that expires unsent actions, as in [BRC-177](/brc/wallet/0177.md), MUST NOT expire or reclaim the inputs of a released bundle. A future portable statement of that promise, if specified, SHOULD be signed by the key that controls the spent input, not a wallet identity, MUST NOT be forwarded beyond the direct payee, and is optional for the payee to require. Otherwise it would reveal every earlier payer to every later payee.
* **Capability.** A wallet that accepts bundles MAY advertise BRC-205 attribute `brc175-offline=2` for this revision. Value `1` does not establish support for derived-key attestations or held outcomes. A payer that cannot tell whether the payee accepts bundles SHOULD settle online first.

## Bindings

### Nearby session

The payee starts a payment by showing a session QR:

```
bsvpay1:<base64url, unpadded, of UTF-8 JSON>
```

| Member   | Type                         | Why                                                                                                                                                                                             |
| -------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `v`      | integer `2`                  | Session format version.                                                                                                                                                                         |
| `s`      | base64url of 16 random bytes | Session ID. It names the radio rendezvous and is burned after one payment, so a bundle cannot be replayed.                                                                                      |
| `k`      | base64url of 32 random bytes | Pre-shared key that seals the bundle, so only this payee can read it.                                                                                                                           |
| `i`      | compressed key, 66 hex       | Payee identity key `B`. The payer derives the payee's output key toward it.                                                                                                                     |
| `p`, `x` | strings                      | Payee-chosen derivation prefix and suffix. They make the output key fresh and tie the bundle to this session.                                                                                   |
| `a`      | decimal string, optional     | Requested amount in token base units, up to uint64. Absent means the payer chooses.                                                                                                             |
| `t`      | object                       | `i`: asset ID. Optional `k`: array of attester keys the payee trusts, as a hint so the payer can choose evidence the payee will accept. Optional `n`, `s`, `d`: display name, ticker, decimals. |
| `c`      | integer, optional            | Transport capability bits, so the payer picks a radio both phones support.                                                                                                                      |

The payer replies with one sealed frame:

```
0x01 ‖ IV (32 bytes) ‖ AES-256-GCM ciphertext of the bundle ‖ tag (16 bytes)
```

The key is the session PSK. A wrong key or any tampering fails authentication, which maps to `decode_failed`. The frame travels by whichever radio both sides support. Radio link details are implementation-specific. If no radio works, the payer shows the sealed frame as a [BRC-141](/brc/peer-to-peer/0141.md) animated QR; 1024-byte blocks are suggested. A sealed frame MUST NOT exceed 65,536 bytes.

The payee answers over the radio with a UTF-8 JSON ack of at most 4,096 bytes:

```json
{ "ok": true }
{ "ok": false, "error": "not_covered" }
```

A held payment is acked as `{ "ok": true, "held": true }`: the payee has stored it but credited nothing, so a merchant SHOULD NOT treat it as paid.

`error` is one of `decode_failed`, `invalid_tx`, `session_mismatch`, `already_paid`, `not_covered`, `limit_exceeded` and `save_failed`. A negative ack means the payee kept nothing. It does not free the payer's inputs; see payer exposure under Settlement. The QR fallback has no return path. The payer then treats the payment as delivered but unconfirmed: it keeps its reservation and does not submit until it learns of acceptance.

### Message box

For payments to a remote payee, the payer sends the bundle through a BRC-33 message box named `color-payments`. It may first resolve a [BRC-169](/brc/peer-to-peer/0169.md) handle to the payee's identity key. The message body is:

```json
{ "v": 1, "bundle": "<standard base64 of the bundle>" }
```

With no session, the payer chooses the derivation prefix and suffix. They MUST be fresh random values. The payee runs the acceptance checks, skipping step 8. It acknowledges the message only after step 10, including for a held payment, or after a decline. The payee SHOULD send its outcome back to the payer's `color-payments` box as `{ "v": 1, "tip": "<txid>", "ok": true }`, with `"held": true`, or with `"ok": false` and an `error` code. When a held payment later resolves, it sends the final outcome the same way.

## Sender blinding

A payer MAY hide its identity from the payee. It picks a fresh random scalar `r` and sends `senderKey = A′ = A + r·G`. It derives the payee's key from the shared secret `S′ = S + r·B`, where `S` is its BRC-42 shared secret with `B`. Because `b·A′ = S′`, the payee derives the same key with an unchanged `getPublicKey` call and `counterparty: A′`. The payee cannot tell a blinded payment from an unblinded one, or from a [BRC-228](/brc/payments/0228.md) ephemeral key. Unblinded payment, with `senderKey = A`, is equally valid.

The payer keeps `r` privately, against the payment's outpoint. Revealing `r` later proves that the payer built the payment: anyone can check `A′ − r·G = A`. `r` never appears in a bundle, in an overlay submission or in BRC-100 metadata.

What each party learns:

| Party                        | Payer identity | Payee identity |
| ---------------------------- | -------------- | -------------- |
| Payee                        | `A′` only      | itself         |
| Overlay of a regulated asset | `A`            | `B`            |
| Public chain                 | neither        | neither        |

Blinding gives privacy from counterparties and the public. It deliberately gives none from a regulated overlay.

## Counterparty risk and double-spend attribution

### The risk

An attestation shows that an output was admitted, not that it is still unspent. Until the payee settles, the payer can spend the same input to someone else. Whoever settles first wins; the other payee's credit is removed. Deferred admission puts that risk on the payee who accepted it. Issuer supply is never affected, because the overlay admits only one spend of each output.

The payee's limits bound the exposure. For regulated assets, attribution makes cheating traceable and therefore deterrable.

### Regulated assets

A regulated asset is one whose overlay admits an output only when the submission discloses the output's owner and that owner is registered with the asset's identity registrar. Those admission controls belong to an optional issuer-controls profile declared in the asset's BRC-162 `req` map. This BRC does not define that profile; it states what attribution needs from it.

* **Ownership disclosure.** For each token output, the submission carries a BRC-69 specific linkage, encrypted to the overlay key under BRC-72. The linkage lets the overlay recompute the output key as `owner + k·G` and match it to the script. For a blinded output, the payer discloses the offset `k` it derived from `S′`.
* **Owner record.** The overlay MUST keep the owner identity key of every admitted output. It MUST keep that record after the output is spent, and record the txid of the spend it admitted.
* **Conflict record.** The overlay SHOULD keep the bytes of any refused submission that tried to spend an already spent output.

Only the owner can spend an output: its private key is `b + k`, and the payer knows `k` but not `b`. So the identity key recorded as the owner of a double-spent outpoint is the identity that signed both spends, unless that key was stolen or shared.

### Reporting a double spend

1. The victim's wallet reports the double-spent outpoint, the bundle it holds and the competing txid from settlement. The bundle contains the second spend, signed by the offender's key.
2. The overlay operator looks up the outpoint's owner record. That gives the owner identity key and the transaction the overlay admitted.
3. The registrar maps the identity key to the person who registered it.

The outpoint is enough to start the lookup. The victim's bundle is the proof. Blinding does not hinder either step, because the overlay saw the real keys. Access to owner records, and the legal process for disclosure, are governed by the operator's and registrar's terms. Those terms are outside this BRC.

For assets without ownership disclosure, attribution stops at the overlay's view of the transactions. There is no person behind a key.

## Security considerations

* **PSK exposure.** Anyone who photographs the session QR can open the sealed frame. They learn the payment but cannot redirect it, because the output pays the payee's key. Payees SHOULD show session codes only briefly.
* **Replay.** A session is burned when its payment is saved. A message-box bundle is unique by tip txid, and saving it twice MUST be idempotent.
* **Attester compromise.** A stolen attester key can attest outputs that were never admitted, and wallets trusting it would accept them. Settlement would then fail, and those payees lose the credited value. Wallets SHOULD let users remove a trust anchor quickly, and overlays SHOULD rotate keys under BRC-189's rules for trust changes.
* **Eviction.** If an admitted transaction is later evicted, for example because it never confirmed, its outputs are no longer admitted. A settled payment can then be reversed. Wallets SHOULD show an evicted credit as reversed, not silently hide it.
* **Stale trust.** Removing a trust anchor does not revoke attestations already relied on. Wallets SHOULD re-check pending `color_offline` outputs against current anchors.
* **Early broadcast.** Anyone holding a signed tip can broadcast it before the overlay admits it, including someone who photographed the session QR and opened the sealed frame. If the overlay then refuses it, for example because an input is frozen, the token units are destroyed on-chain. For assets under issuer controls the issuer's remedy is reissue under that profile. Payees SHOULD settle promptly to narrow the window.
* **Chained refusals.** A final refusal orphans every descendant in a chain of offline payments. So one double spend can hurt every good-faith payee downstream, and per-wallet depth limits are the only bound on how many. Wallets SHOULD keep depth limits low for high-value assets.
* **Size.** Decoders MUST bound allocation by the received length before reading counts. Walk depth and BEEF size MUST be bounded.

## Test vectors

All keys below are test values. Never use them for real funds.

### Blinded derivation

| Item                           | Value                                                                |
| ------------------------------ | -------------------------------------------------------------------- |
| payer private key `a`          | `0000000000000000000000000000000000000000000000000000000000000457`   |
| payee private key `b`          | `00000000000000000000000000000000000000000000000000000000000008ae`   |
| blinding factor `r`            | `0000000000000000000000000000000000000000000000000000000000000d05`   |
| `A`                            | `0228b7f3a019749cce6fc677afa8fae72ec10e811ed4b04e1963143cef87654b75` |
| `B`                            | `0271b357df56cfc77291b75e5f550d72687c1bef84ff9eadb4946eb55516a89d6f` |
| `A′ = A + r·G`                 | `024d4dd4c2ad973e10065a593d0203dda4174292bb36e4e99fb2fbb1373a17874b` |
| asset ID                       | `a1a1…a1_0` (`a1` × 32, then `_0`)                                   |
| prefix, suffix                 | `AQ==`, `Ag==`                                                       |
| protocol name                  | `p color a1a1…a1v0 41513d3d 41673d3d`                                |
| invoice                        | `2-p color a1a1…a1v0 41513d3d 41673d3d-color`                        |
| `S′ = a·B + r·B`               | `035a21815b3303fdba64ea2822232d22a91fbc2ad2e5eee4f18b3308d6b7350e8a` |
| `k = HMAC-SHA256(S′, invoice)` | `d093c0c52c9228a51a2641a963aeb3b370070494a3ec750cd2c2c500ab4d458a`   |
| payee key `P = B + k·G`        | `02b2fd0a551e8e3e3eabcb97acc52b5b16f3a1ab18472cddbe0b54cbcd5d6c05e7` |
| HASH160(`P`)                   | `7cd27b9db3068175b6a8122e42034a298e547996`                           |

The payee's unchanged `getPublicKey({protocolID, keyID: "color", counterparty: A′, forSelf: true})` returns `P`.

### Attestation

| Item                                    | Value                                                                                                                                          |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| attester private key                    | `00000000000000000000000000000000000000000000000000000000000015b3`                                                                             |
| attester identity key (`signerKey`)     | `02798b81951a6a8c7ef8beda09b06a23031d7efaf37b663265e0188ab378124046`                                                                           |
| invoice                                 | `2-color admission attestation-1`                                                                                                              |
| derived signing key (anyone derivation) | `033520aaa77b6914019796e974d1737acc890c5283c0921ddcfc2d5c815db8fb90`                                                                           |
| message                                 | `1color-admit:v1:tm_color_a1a1…a1_0:c3c3…c3:0,2`                                                                                               |
| `e = SHA-256(message)`                  | `7774ec9347afe70b376d452746c9aa4ef7a11205a35dc92bf3866d8b32d0a9f0`                                                                             |
| signature (RFC 6979, DER)               | `304402207fc9b223eb7d3dc5817804320a490404b47f5247efbaa3089080d38c376dd713022003a71ceddfb40e36db48c11f50e202426e76b42c0aa47c886e980f4dba87ee1c` |

`a1a1…a1` and `c3c3…c3` stand for the byte repeated 32 times (64 hex characters).

**Negative case.** This signature over the same `e`, made with the bare attester identity key, MUST be rejected:

```
304502210084f2172ef0fdd4a01038af38f00b339133580eca3393e5989df9688bf9462e58022042a1b88ca1750fef4b7aa0466bcfebd2d9c6bb1f4333fadce2ef2504471ace67
```

### Bundle encoding

This vector covers framing only. Its `transaction` is four placeholder bytes, not valid BEEF.

* `senderKey`: `A′` above.
* `outputIndex`: 1.
* prefix and suffix: as above.
* `assetId`: as above.
* One submission: txid `b2` × 32, off-chain values `{}`.
* One attestation: the one above, with `signerKey` the attester identity key.
* Empty note.
* `transaction`: `01010101`.

```
01024d4dd4c2ad973e10065a593d0203dda4174292bb36e4e99fb2fbb1373a17874b0104
41513d3d0441673d3d426131613161316131613161316131613161316131613161316131
613161316131613161316131613161316131613161316131613161316131613161316131
61315f3001b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2
b2027b7d01c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3
c302000246304402207fc9b223eb7d3dc5817804320a490404b47f5247efbaa3089080d3
8c376dd713022003a71ceddfb40e36db48c11f50e202426e76b42c0aa47c886e980f4dba
87ee1c02798b81951a6a8c7ef8beda09b06a23031d7efaf37b663265e0188ab378124046
000401010101
```

Length: 294 bytes. The line breaks are for display only.

## Implementations

A prior version of this protocol is implemented in the BSV wallet (`bsv-wallet`, `packages/expo-wallet-toolbox/core/localpay` and `core/mandala`) with the `@bsv/mandala` library and its Go overlay. That implementation predates the 1Color names and this bundle encoding, and is being migrated to this specification.

## References

* [BRC-22](/brc/overlays/0022.md): Overlay Network Data Synchronization
* [BRC-33](/brc/peer-to-peer/0033.md): PeerServ Message Relay Interface
* [BRC-42](/brc/key-derivation/0042.md), [BRC-43](/brc/key-derivation/0043.md): key derivation and invoice numbers
* [BRC-62](/brc/transactions/0062.md), [BRC-95](/brc/transactions/0095.md), [BRC-233](/brc/transactions/0233.md): BEEF, Atomic BEEF and Subject BEEF
* [BRC-69](/brc/key-derivation/0069.md), [BRC-72](/brc/key-derivation/0072.md): key linkage revelation
* [BRC-141](/brc/peer-to-peer/0141.md): Fountain-Coded Air-Gap Transport
* [BRC-162](/brc/tokens/0162.md): 1Color tokens
* [BRC-169](/brc/peer-to-peer/0169.md): handle addressing
* [BRC-176](/brc/tokens/0176.md): BSV-21 validity proofs
* [BRC-177](/brc/wallet/0177.md): wallet-enforced expiry for `noSend` actions
* [BRC-189](/brc/wallet/0189.md): identity and personal trust
* [BRC-205](/brc/wallet/0205.md): wallet version attributes
* [BRC-207](/brc/wallet/0207.md): 1Color wallet module
* [BRC-228](/brc/payments/0228.md): unlinkable payments


---

# 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://hub.bsvblockchain.org/brc/payments/0175.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.
