In plain language
Two halves, one record
Most Bitcoin metaprotocols let one holder move one thing. Tandem does not. A Tandem object lives in a Bitcoin output that can only be spent when two specific keys both sign. The protocol layer then insists that the spend has the exact shape of one of five defined operations. Miss either requirement and there is no Tandem record.
SIDE A The first half
One participant key. It authorizes an input, receives an output, and is committed to by the carrier script. On its own it can do nothing to the object.
SIDE B The second half
The counterpart key. Sorted after side A by raw byte order, so the pair has one unambiguous written form. On its own it can do nothing to the object either.
The pairing requirement is not a policy that some service enforces. It is the shape of the Bitcoin output itself: an exact 71-byte 2-of-2 witness script, wrapped in native P2WSH. Bitcoin consensus refuses an unmatched spend before any Tandem software is consulted. Tandem then adds a second, stricter layer on top: even a correctly signed 2-of-2 spend produces no valid Tandem state unless the whole transaction matches an exact template.
Side A, the lower-sorted key Side B, the higher-sorted key Inert, no protocol effect
Where pairing appears
Five places a pair must match
Pairing is not one rule. It runs through the entire protocol, and each appearance has its own failure code. This is the quickest way to understand what Tandem actually enforces.
| Pairing | Requirement | Reason on failure |
|---|---|---|
| Key pair | Two valid, distinct, compressed secp256k1 keys with key0 < key1 by unsigned bytewise order |
BAD_KEY_ORDER_OR_BINDING (0x0015) |
| Signature pair | Four witness elements: empty, signature for key0, signature for key1, witness script, in that order | BAD_SIGNATURE_OR_SIGHASH (0x0016) |
| Predecessor and successor | The marker state_seq is exactly the consumed carrier's sequence plus one |
BAD_STATE_SEQUENCE (0x001b) |
| Carrier continuity | MARK reproduces the predecessor carrier script byte for byte; ROTATE derives the successor carrier from the new pair | BAD_SUCCESSOR (0x001c) |
| Payout pair | CLOSE and REFUND pay key0 and key1 exactly equal, strictly positive amounts | BAD_FEE_SPLIT_OR_CHANGE (0x0019) |
The last row is worth pausing on. A cooperative ending does not let one side take more than the other. The exit is symmetric by rule, not by agreement, so neither participant has to trust the other's arithmetic at the moment the object ends.
The object
One carrier, five operations, three endings
An active Tandem object is exactly one unspent output, called the carrier: 20,000 satoshis at a native P2WSH address derived from the current key pair. Every operation consumes that carrier and, unless it is terminal, produces the next one.
| Operation | Opcode | Inputs | Outputs | Effect on the object |
|---|---|---|---|---|
| INIT | 0x00 | 1 | 2 | Activates one protocol identifier. Creates no object. |
| CREATE | 0x01 | 2 | 4 | Object begins ACTIVE at sequence 0. |
| MARK | 0x02 | 2 | 3 | Sequence plus one, chapter count plus one, keys unchanged. |
| ROTATE | 0x03 | 3 | 4 | Sequence plus one, keys replaced, chapter count unchanged. |
| CLOSE | 0x04 | 1 | 3 | Sequence plus one, status CLOSED, no successor. |
| REFUND | no marker | 1 | 2 | Sequence unchanged, status REFUNDED, no successor. |
There is also a fourth outcome nobody chooses. If a confirmed transaction consumes an
active carrier but fails to validate as one of these operations, the object terminates
as EXITED_NONCANONICAL. The spend cannot be ignored, because the output it
depended on no longer exists. Tandem never combines, splits, or forks an object.
The Bitcoin Universe capability snapshot records 38 protocols, 29 of which have a marketplace entry. Tandem is not among the 38. No Universe product implements a buy, sell, list, or transfer path for a Tandem object, and this repository does not describe one. Tandem defines shared control and a history, not a tradable asset.
Why you can check this yourself
Two implementations, two languages, one answer
A deterministic protocol is only as trustworthy as your ability to disagree with its author. Tandem is implemented twice, independently, in two different languages, and the two implementations share nothing but frozen bytes.
PIPELINE A TypeScript indexer
bitcoinuniverseio/index-tandem resolves Bitcoin data, classifies transactions, and serves object state over HTTP.
PIPELINE B Rust verifier
bitcoinuniverseio/tandem-verifier-rs reimplements the parser, reducer, and roots in Rust and refuses to import pipeline A at all.
The two pipelines never read each other's output. They agree, or fail to agree, only by publishing signed tuples for the same block height and comparing them. That comparison is the real trust property, and the verifier page explains exactly what it does and does not prove.
Where to go next