Transaction IDs
Every transaction needs a name — a unique handle other transactions can point at when they spend its outputs. That handle is the transaction id, or txid. It isn’t assigned by anyone; it is derived from the transaction’s own contents by hashing. This page shows exactly how, why that’s a beautiful property, and why the legacy version of it once had a subtle, expensive flaw.
A txid is a fingerprint of the transaction
Section titled “A txid is a fingerprint of the transaction”To get a transaction’s id you serialize the transaction into its canonical byte form and run it through SHA-256 twice — Bitcoin’s ubiquitous double-SHA-256:
serialized transaction bytes │ ▼ SHA-256 │ ▼ SHA-256 │ ▼ 32-byte digest = the txidBecause a hash function is deterministic and collision-resistant, this has two consequences that matter enormously:
- The id is self-certifying. Anyone with the transaction bytes can recompute the id and confirm it. The name is of the thing, not assigned to it — there’s no registry to trust.
- The id is tamper-evident. Change a single satoshi in any output and the bytes change, so the double-SHA-256 changes, so the txid changes. You cannot alter a transaction and keep its name.
How coins are addressed: (txid, index)
Section titled “How coins are addressed: (txid, index)”A transaction can have several outputs, so the txid alone doesn’t name a coin — it names the
transaction. To point at one specific output you also need its position in the output list, the
index (also called vout), counting from 0. The pair is called an outpoint:
outpoint = (txid, index)
txid = f1a9...e3 index = 0 → the first output of that tx txid = f1a9...e3 index = 1 → the second output (e.g. the change)This is precisely the pointer an input carries when it spends a
coin. The entire ledger is a web of these references: every input names a prior (txid, index), and
the UTXO set is just the collection of outpoints that no
input has yet referenced. Spending a coin = adding an input that points at its outpoint, which
removes that outpoint from the unspent set.
tx_A ─ out[1] ───────────────► spent by ─── tx_B in[0] points at (txid_A, 1) (a UTXO until now) (the coin is now consumed)A subtle, costly flaw: signatures inside the legacy txid
Section titled “A subtle, costly flaw: signatures inside the legacy txid”Here is the catch that took years to fully resolve. In legacy (pre-SegWit) transactions, the
unlocking data — the scriptSig, which contains the signature — was part of the bytes hashed into
the txid. That sounds harmless until you realize a signature has several valid encodings. A third
party with no key at all could take a broadcast-but-unconfirmed transaction, re-encode its signature
into another valid form, and rebroadcast it. The transaction would still be valid and still spend the
same coins to the same places — but its bytes changed, so its txid changed.
original tx ──► txid = ABCD... │ attacker tweaks the signature encoding (no key needed) │ ▼ same effect, different bytes ──► txid = WXYZ... ← mutated!This is transaction malleability, and it broke any system that referred to a transaction by an
id it predicted before the transaction confirmed (early payment channels, exchanges that tracked
withdrawals by txid). The fix — SegWit — moved signatures into a separate witness field that is
excluded from the legacy txid computation, so the id now depends only on data the spender can’t
have tampered with after signing. The full story, and the additional wtxid, live in
Transaction malleability.
Under the hood — the txid you see is byte-reversed
Section titled “Under the hood — the txid you see is byte-reversed”Try to verify a txid by hand and you hit a baffling wall: double-SHA-256 the raw bytes and the digest you get is the txid backwards. Bitcoin computes the hash over the serialized transaction and keeps the result in internal (little-endian) byte order, but every block explorer, wallet, and RPC call displays it reversed, byte for byte.
internal hash bytes : e3 ... a9 f1displayed txid : f1 a9 ... e3 ← same 32 bytes, reversedThis is purely a display convention with deep historical roots, but it bites everyone the first time. The fix is mechanical: reverse the 32-byte digest before comparing it to what an explorer shows. The same reversal applies to block hashes — which is why real block hashes are quoted with a long run of leading zeros rather than trailing ones.
The thread
Section titled “The thread”How do txids help untrusting strangers agree on one ledger? They give every transaction a name that anyone can independently verify and no one can forge. Because the name is the hash of the contents, two strangers who have never communicated will compute the same id for the same transaction and different ids for any two different transactions — no coordination, no authority, no trust. That shared, content-derived naming is what lets inputs unambiguously reference earlier outputs across the whole network: the ledger is stitched together entirely out of hashes that each node can check for itself.
The architect’s lens
Section titled “The architect’s lens”Step back from the double-hash and answer the five questions an architect asks of any naming scheme:
- Why does it exist? To give every transaction a unique handle that other transactions can point at when they spend its outputs — derived from the transaction’s own bytes by double-SHA-256, not assigned by any registry.
- What problem does it solve? Trustless, forgery-proof naming: because the name is the hash of the
contents, two strangers compute the same id for the same transaction and different ids for any two
different ones — and the
(txid, index)outpoint becomes the pointer that stitches the whole ledger together. - What are the trade-offs? Content-derived names are tamper-evident but also fragile to encoding
changes. Legacy txids hashed the
scriptSig— which holds the signature — so a third party with no key could re-encode the signature and mutate the id: transaction malleability. - When is it the wrong design? When you need to reference a transaction by a predicted id before
it confirms — exactly what broke early payment channels and exchanges. The fix wasn’t a different
naming scheme but excluding the malleable witness from the hash (and adding the
wtxid). - What breaks if I remove it? With no content-derived id, inputs couldn’t unambiguously reference earlier outputs — you’d need a trusted authority to assign and vouch for names, the very thing the ledger exists to avoid. (Mt. Gox in 2014 showed the cost of trusting a txid before it confirms.)
Check your understanding
Section titled “Check your understanding”- How is a txid computed, and why does that make it self-certifying and tamper-evident?
- Why isn’t the txid alone enough to identify a coin — what else is needed, and what is the pair called?
- Describe how the UTXO set relates to outpoints and to spending.
- What is transaction malleability, and why was it possible specifically for legacy txids?
- How did SegWit fix malleability, and what is the difference between a txid and a wtxid?
Show answers
- The txid is double-SHA-256 of the serialized transaction bytes (
SHA-256(SHA-256(x))), yielding a 32-byte digest. Because hashing is deterministic, anyone with the bytes can recompute the id (self-certifying — no registry to trust); because it’s collision-resistant, changing a single satoshi changes the bytes and thus the id (tamper-evident). - The txid names the transaction, but a transaction can have several outputs, so you also need the output’s index (
vout, counting from 0). The pair(txid, index)is called an outpoint, and it uniquely names one coin. - The UTXO set is just the collection of outpoints that no input has yet referenced. Spending a coin means adding an input that points at its outpoint, which removes that outpoint from the unspent set — the whole ledger is a web of these
(txid, index)references. - Transaction malleability is when a third party with no key re-encodes a broadcast-but-unconfirmed transaction’s signature into another valid form, changing its bytes and therefore its txid while it still spends the same coins to the same places. It was possible for legacy txids specifically because the
scriptSig(which holds the signature) was part of the bytes hashed into the txid. - SegWit moved signatures into a separate witness field that is excluded from the legacy txid computation, so the id now depends only on data the spender can’t tamper with after signing. A transaction then has two hashes: the txid (excludes witness, stable and non-malleable) and the wtxid (includes witness, used for relay and the witness Merkle commitment).