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 genuine CoinJoin from our reference signer (testnet — the byte layout is identical on mainnet). Five inputs, two equal outputs, a change output and the coordinator fee:
version 01000000 version 1
marker,flag 00 01 this is a SegWit tx
input count 05 5 inputs
input #1
txid 735ea5f0..c235608 32 B, internal byte order
vout 00000000 spends output index 0
scriptSig 00 empty — it is in the witness
sequence fdffffff opt-in RBF
inputs #2–#5: same 41-byte shape, a different UTXO each (one per participant)
output count 04 4 outputs
out #1 8038010000000000 0014 a29a73..0f34 80,000 sat — equal
out #2 8038010000000000 0014 ac9143..a0bd 80,000 sat — equal (anon set)
out #3 f12a010000000000 0014 b30667..f0c2 76,529 sat — change
out #4 5d09000000000000 0014 a5ec1d..52c7 2,397 sat — coordinator fee
witness #1 02 48 3044..01 21 03..d280 [ signature, pubkey ]
witnesses #2–#5: one stack per input — each participant's own signature
locktime 00000000 spendable immediately
The two identical 80,000-sat outputs are the anonymity set; 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.
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 example above is 880 bytes on the wire, but for fees it counts as a weight of 1,897 units, i.e. about 475 vbytes (weight ÷ 4). The fee itself is simply what is left over: inputs − outputs = 239,726 − 238,926 = 800 sat (≈ 1.7 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.