Anatomy of a signed CoinJoin¶
Low-level — byte by byte
A Bitcoin transaction is just a byte string: a list of inputs it unlocks and outputs it locks. A CoinJoin is one such string that many people build and sign together — here it is field by field, using a real CoinJoin our reference signer broadcast.
Structure¶
Every SegWit transaction serializes to the same fields, in this order:
| Field | Size | Format | Description |
|---|---|---|---|
| version | 4 bytes | little-endian | transaction format version |
| marker | 1 byte | 00 |
flags a SegWit transaction |
| flag | 1 byte | 01 |
witness data is present |
| input count | varint | compactSize | number of inputs |
| txid | 32 bytes | reversed | the UTXO being spent |
| vout | 4 bytes | little-endian | which output of it |
| scriptSig size | varint | compactSize | 00 for SegWit inputs |
| sequence | 4 bytes | little-endian | RBF / locktime signalling |
| output count | varint | compactSize | number of outputs |
| amount | 8 bytes | little-endian | value in satoshis |
| scriptPubKey | varies | script | where the coins go |
| witness | varies | stack per input | the signatures (SegWit) |
| locktime | 4 bytes | little-endian | earliest spend height/time |
Two encodings to keep in mind: numbers are little-endian, and lengths/counts use compactSize
varints (one byte under 253; an fd prefix + two bytes up to 65,535).
A CoinJoin, byte by byte¶
A real transaction our reference signer broadcast on testnet4 —
f051aaf0..2a843476e.
Eight inputs, six equal pool outputs, a change output and the coordinator fee. It spends the outputs
of an earlier round, 05def0ad..1666edd0.
version 01000000 version 1
marker,flag 00 01 SegWit transaction
input count 08 8 inputs
input #1
txid d0ed6616..adf0de05 32 B, internal (reversed) order — this is 05def0ad..1666edd0
vout 00000000 spends its output #0
scriptSig 00 empty — the signature is in the witness
sequence fdffffff opt-in RBF (BIP-125)
inputs #2–#8: identical 41-byte shape, vout 01000000 … 07000000
output count 08 8 outputs
out #1 8038010000000000 0014 c73a9f99..a4fbe34b 80,000 sat ┐
out #2 8038010000000000 0014 9d5f0b3b..535ad129 80,000 sat │
out #3 8038010000000000 0014 bde75497..0ef7fd74 80,000 sat ├ equal pool outputs
out #4 8038010000000000 0014 d386d5bc..d8e418ae 80,000 sat │ (the anonymity set)
out #5 8038010000000000 0014 a3823ba9..67232424 80,000 sat │
out #6 8038010000000000 0014 9ca891f7..8f82fad5 80,000 sat ┘
out #7 e5e5000000000000 0014 ba804126..7c9842ff 58,853 sat change
out #8 5315000000000000 0014 c73a9f99..a4fbe34b 5,459 sat coordinator fee
witness #1 02 47 3044..5a37b54f..95d 01 21 0277a493..3831ffa4
└ 2 items: [ 71-byte DER signature + SIGHASH_ALL byte ] , [ 33-byte compressed pubkey ]
witnesses #2–#8: one stack per input — each input signed on its own
locktime 00000000 spendable immediately
The six identical 80,000-sat outputs are the pool; the larger output is change and the smallest is the coordinator fee. Inputs carry no signature inline — every signature lives in the witness section, one stack per input. That separation is what lets many people's signatures be assembled into one transaction.
This round was a single-participant test
testnet4, and one wallet — it exercises the full pipeline (batching, fee + commission split, signature collection, broadcast), not a multi-party anonymity set. The byte layout of a multi-participant round is identical; the inputs and their witnesses just belong to different owners. See the Verify page for the list of rounds, and the mainnet example at the end of this page for what it looks like at scale.
What each participant signs¶
A signature does not cover an input in isolation — it commits to the whole transaction through a sighash. For SegWit v0 (BIP-143) the hashed message is, in essence:
sighash = dSHA256(
nVersion,
hashPrevouts, // hash of ALL inputs' (txid, vout)
hashSequence, // hash of ALL inputs' sequences
thisOutpoint, scriptCode, thisAmount, thisSequence,
hashOutputs, // hash of ALL outputs (value + script)
nLocktime, SIGHASH_ALL )
- It commits to every input and every output. With
SIGHASH_ALLyour signature means "I approve exactly these inputs and exactly these outputs." - Nothing can change after you sign. Add, drop, reorder or retarget anything and every signature breaks — so handing a half-built CoinJoin to a coordinator is safe.
- Signatures merge independently. Each participant signs only their own inputs; the coordinator drops each witness into the matching slot. Keys are never shared.
- Taproot inputs use the BIP-341 sighash and a 64-byte Schnorr signature, but the principle is identical.
TXID and wTXID¶
A transaction has two identifiers, both double-SHA256 hashes — but over different bytes:
- txid = hash of the non-witness fields only (version, inputs, outputs, locktime).
- wtxid = hash of the full serialization, including marker, flag and all witnesses.
Because the txid excludes the witness, adding signatures does not change the txid. That is exactly why participants can sign in turn and have their witnesses merged: the transaction they each signed keeps the same txid throughout.
Size, weight and fee¶
Witness bytes are discounted 4×. The transaction above is 1,446 bytes on the wire, but for fees it counts as a weight of 3,204 units, i.e. 801 vbytes (weight ÷ 4). The fee itself is simply what is left over: inputs − outputs = 545,947 − 544,312 = 1,635 sat (≈ 2.0 sat/vB). No field stores the fee; miners compute it from the difference.
At scale: a real mainnet CoinJoin¶
The same structure, with hundreds of participants. A confirmed Wasabi (WabiSabi) CoinJoin on mainnet,
tx 198aee6e..b3ef9b70, block 755,972:
| Field | Value |
|---|---|
| Inputs | 374, from many independent owners |
| Outputs | 408 |
| Virtual size | 68,012 vbytes |
| Fee | 93,558 sat (≈ 1.4 sat/vB) |
| Scripts | all native SegWit (P2WPKH) |
The outputs cluster on shared denominations (powers of 2 and 3). Each repeated value is an anonymity set — 43 distinct denominations in that one transaction, so identical chunks from different users become interchangeable.
Note
Many inputs, each signed independently; equal outputs no one can tell apart; one transaction, one shared fee — and nothing in it can change without every signer noticing.