008 · Buyer arbitrated content retrieval specification
008 completes the 007 custody story with the Buyer pickup path. When Seller
and Buyer cannot reach each other directly but both can reach the Arbiter,
the Seller still custodies the exact payload bundle through Kind 8 and the
Arbiter still signs the paid receipt through Kind 9. The Buyer locates that
custody record with an independently computable ArbitrationClaimID, proves
itself with a unified SignWireDocument(1, 10, ...) signature under its own
buyer key, and receives an Arbiter-signed Kind 11 that either binds the exact
payload bundle or answers with a structured unavailable reason.
This is a one-shot hard switch: Kind 10 and Kind 11 exist only in the shapes below. There is no legacy decoder, no feature flag, no dual shape, and no field-presence guessing.
Wire documents
Kind 10 · ContentRetrievalRequest (Buyer → Arbiter)
The wire truth is [1, 10, content_retrieval_request_cbor, buyer_content_retrieval_request_signature]:
ContentRetrievalRequest = [
1,
10,
content_retrieval_request_cbor,
buyer_content_retrieval_request_signature
]
content_retrieval_request_cbor = [
arbitration_claim_id,
retrieval_nonce
]
Constraints:
arbitration_claim_id = bstr .size 32
retrieval_nonce = bstr .size 32 ; MUST NOT be all zero
buyer_content_retrieval_request_signature = bstr .size (1..256)
The request carries nothing else. It does not repeat the Buyer public key, RefundTemplateTxID, PaymentAuthorizationID, OpeningProof, the payment authorization document, or the Claim bytes: the Arbiter recovers every role key from the stored Claim named by the Claim ID inside the signed request document. The maximum wire size is derived from the subfield limits: 1 array head + 1 version + 1 kind + (3 + 69) + (3 + 256) = 334 bytes.
Buyer signing domain
WireSignatureInput(1, 10, content_retrieval_request_cbor)
= deterministic-CBOR(["bitfs/wire-signature", 1, 10, content_retrieval_request_cbor])
buyer_content_retrieval_request_signature =
SignWireDocument(BuyerKey, 1, 10, content_retrieval_request_cbor)
SignWireDocument is the fixed project semantic: build the typed signing
input above, SHA-256 once, then a low-S DER ECDSA signature. The Buyer never
signs the bare Claim ID bytes, the bare nonce bytes, any string concatenation,
hex, JSON, the complete four-element wire message, or an arbitration
transaction sighash.
The nonce is generated by the Buyer application from a cryptographic random source and passed explicitly into the SDK. The SDK never generates, stores, or deduplicates nonces; timestamps, counters, Claim ID prefixes, and all-zero values are all invalid nonces.
Nonce one-time and replay semantics
content_retrieval_request_id (SHA-256 over the exact request document)
maps one-to-one onto (arbitration_claim_id, retrieval_nonce). The arbiter
application MUST:
- occupy
(Claim ID, Nonce)atomically — after buyer authentication, before signing — for everynot_ready,custody_gone, andavailableanswer, and persist the first signed Kind 11 as that request's only answer; - resend the first persisted Kind 11 verbatim whenever the same
content_retrieval_request_idreplays; a later status change never upgrades a capturednot_readyinto an authorization; - require a fresh nonce (and a fresh signature) for every retry after a
not_readyanswer; - treat
seller_arbitration_not_receivedas the single exception: no Claim means no authentication is possible, so nothing is occupied or persisted, but such queries must be rate-limited and must not leak record metadata; - keep nonce records at least as long as the custody record, and delete cached first answers together with the content when retention ends.
Claim ID reuse
The Claim ID algorithm is unchanged from 007:
ArbitrationClaimID = SHA-256(exact_arbitration_claim_cbor)
Because the ID binds the exact claim document — which in turn binds the pool source context, the refund template raw bytes, the Buyer-signed payment authorization, and the ordered content hashes — the Buyer can compute the identical Claim ID from only its OpeningProof plus the exact signed payment authorization. No Seller Claim signature, payload, or Kind 9 is required on the Buyer side.
Kind 11 · ContentRetrievalResponse (Arbiter → Buyer)
Kind 11 is an explicitly discriminated two-branch union signed by the Arbiter
through SignWireDocument(1, 11, ...). The discriminator lives inside
content_retrieval_result_cbor and selects the only legal outer shape; there
is no presence guessing.
content_retrieval_result_cbor = [
content_retrieval_request_id, ; SHA-256(exact content_retrieval_request_cbor)
result, ; 0 unavailable / 1 available
branch_value
]
Unavailable branch (result = 0, exactly four outer elements, no
attachment):
ContentRetrievalResponse = [1, 11, result_cbor, arbiter_content_retrieval_result_signature]
branch_value = content_retrieval_unavailable_reason
; 0 seller_arbitration_not_received
; 1 seller_arbitration_not_ready
; 2 custody_gone
This branch carries no Claim, role keys, payloads, or record metadata. When no custody record exists the Arbiter cannot authenticate the Buyer at all: it answers the structurally valid request ID with the minimal signed negative response and must rate-limit such queries. Once a record or verifiable tombstone exists, the Buyer must be authenticated first.
Available branch (result = 1, exactly five outer elements, attachment
mandatory):
ContentRetrievalResponse = [1, 11, result_cbor, arbiter_content_retrieval_result_signature, content_payloads_cbor]
branch_value = content_payloads_id ; SHA-256(exact content_payloads_cbor)
content_payloads_id binds the number, order, and raw bytes of the returned
bundle without copying up to ~16.8 MB of payload into the signature preimage.
It does not replace the per-item content_hashes_cbor committed by the
Buyer-signed payment authorization: the former proves which exact bundle the
Arbiter returned this time, the latter proves whether those blocks are what
the Buyer originally authorized.
The response does not repeat claim_id, receipt bytes, public keys, OpeningProof, funding transactions, or any raw candidate, and it never claims that the Seller arbitration transaction has been broadcast, mined, or finally settled. Unauthorized, Malformed, RateLimited, and internal storage errors remain transport/application errors and are never dressed up as structured unavailable answers.
Verification chain
Reception of an Available Kind 11 is valid only when all of the following pass:
- strict deterministic decode of Kind 10, then of the result document and its unique branch shape;
- the signed
content_retrieval_request_idequalsSHA-256(exact content_retrieval_request_cbor)of the Buyer's own request; - the Arbiter signature verifies via
VerifyWireDocument(1, 11, ...); content_payloads_idequals the SHA-256 of the attached payload bundle;- payload count, order, sizes, canonical child CBOR, and per-item SHA-256 match the ordered hashes of the locally saved payment authorization.
Acceptance is time-independent: expired quotes, passed delivery deadlines, and matured refunds never invalidate already signed custody evidence inside its retention window. No fake clock or fake block height is involved.
An Unavailable answer never implies that the Seller will never arbitrate, and it produces no refund, pool close, or payment state change.
What 008 deliberately does not do
- No buyer arbitration close, fast refund, forced close, buyer+arbiter
co-signed close transaction, or Seller challenge window exists. If the
seller never submitted 007 or the record is gone, the buyer waits for the
seller or broadcasts its presigned refund transaction after
nLockTime. - Kind 6
ContentDeliveryis not reused andbuyer.AcceptDeliveryis not called: 008 acceptance returns payloads plus audit data and does not produce a PaymentUpdate; it does not sign any buyer transaction, does not modify the previous PaymentState, and does not construct any close transaction. - The Claim ID is not a download token: requests carrying only a Claim ID without a valid Buyer signature never receive content.
- The nonce is not encryption and does not replace TLS: production transports must provide confidentiality, integrity, and arbiter endpoint identity.