Skip to content

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 txid

Because a hash function is deterministic and collision-resistant, this has two consequences that matter enormously:

  1. 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.
  2. 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.

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 f1
displayed txid : f1 a9 ... e3 ← same 32 bytes, reversed

This 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.

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.

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.)
  1. How is a txid computed, and why does that make it self-certifying and tamper-evident?
  2. Why isn’t the txid alone enough to identify a coin — what else is needed, and what is the pair called?
  3. Describe how the UTXO set relates to outpoints and to spending.
  4. What is transaction malleability, and why was it possible specifically for legacy txids?
  5. How did SegWit fix malleability, and what is the difference between a txid and a wtxid?
Show answers
  1. 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).
  2. 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.
  3. 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.
  4. 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.
  5. 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).