You're Not Signing the Whole Thing

You're handed a contract twenty pages long. You initial page seven. That's it. Your initials don't cover the payment terms on page twelve or the exit clause on page nineteen, and nobody pretends they do. Bitcoin's sighash flags work on exactly that logic: each signature carries a one-byte declaration of precisely which parts of the transaction it covers, and the network enforces the boundary.

Change something inside that scope and the signature breaks. Change something outside it and the signature holds, indifferent.

This is not a quirk or an oversight. It is deliberate architecture, and it enables transaction patterns that would be impossible if every signature were forced to cover everything.

The Four Bytes That Do the Work

Bitcoin currently defines four main sighash types, each a constant written into the signature itself at broadcast time.

SIGHASH_ALL (0x01) is the default. The signer commits to every input and every output. Tamper with anything and the signature is void. Most ordinary sends use this, and for good reason: you want the recipient's address locked in before you let go of the transaction.

SIGHASH_NONE (0x02) commits to all inputs but zero outputs. The signer is saying, in effect, "I authorise spending my coin, but I don't care where it goes." That sounds alarming. Used carelessly, it is. Anyone who obtains that signature can redirect the funds. But it has legitimate uses in certain two-party protocols where a second party fills in the outputs later under a separate binding commitment.

SIGHASH_SINGLE (0x03) commits to all inputs and exactly one output: the output whose index matches the input being signed. A signer on input 2 covers output 2 and nothing else. Outputs 0, 1, and 3 can be modified freely without touching the signature.

SIGHASH_ANYONECANPAY (0x80) is a modifier, not a standalone type. It combines with the others using a bitwise OR. When set, the signature covers only the single input being signed, not all inputs. Other inputs can be added or removed by other parties without invalidating anything. SIGHASH_ALL | ANYONECANPAY (0x81) resolves to: "I lock in all outputs and my own input, and I am indifferent to whoever else contributes alongside me."

That combination is what enables crowdfunding-style transactions, where many contributors sign their own inputs independently and no signature breaks when a new participant joins.

A Worked Scenario: The Concert Ticket Pool

Three people, call them Mara, Dev, and Lena, each want to fund a shared multisig wallet. They are not in the same room. They do not trust each other to build the transaction honestly. The organiser wants to collect exactly 0.5 BTC total before broadcasting anything.

Each person constructs a transaction with their own UTXO as an input and the shared address as the single output for the full 0.5 BTC, then signs with SIGHASH_ALL | ANYONECANPAY.

Mara signs her input. Dev signs his. Lena signs hers. Each signature is mathematically bound to its own input and to that output address, 0.5 BTC to the shared wallet, but not to any other inputs. The organiser assembles all three signed inputs into one transaction. Every signature stays valid because ANYONECANPAY told each signer to ignore the other inputs. The network sees a valid three-input transaction and broadcasts it.

No single party could redirect the funds, because SIGHASH_ALL locked the output. No party's signature was invalidated by the others joining. Mara, Dev, and Lena each contributed roughly 0.167 BTC. The math works. The trust model works.

The Bug That Lived in Production

Here is where things get genuinely tricky, and it is the part that catches developers more often than users.

SIGHASH_SINGLE has a famous edge case. If you sign input n with SIGHASH_SINGLE but the transaction has no output at index n, the original Bitcoin code returned a hash of the 32-byte integer 1 rather than a proper transaction hash. Signing that value is effectively signing a known constant. This flaw, sometimes called the SIGHASH_SINGLE bug, meant that such a signature could be replayed in other transactions that hash to the same value. Satoshi-era code. Never patched in legacy transaction formats.

SegWit (BIP143) introduced a revised sighash algorithm for native SegWit inputs that closes this and, critically, also commits to the value of the input being spent. That second fix matters more than it sounds. Under the original scheme, a signer did not commit to how much bitcoin was in the UTXO they were authorising. A malicious coordinator in a multisig setup could substitute a higher-value UTXO and quietly pocket the difference in fees. SegWit closed that hole.

Taproot (BIP341) went further still: Tapscript signatures commit to all input amounts and all scriptPubKeys simultaneously, which makes hardware wallet signing in complex transactions dramatically more auditable.

A Misconception Worth Correcting

People sometimes assume SIGHASH_NONE or ANYONECANPAY are inherently dangerous and should never appear in production. That judgment is too blunt, and it is wrong.

SIGHASH_NONE inside a well-constructed two-party channel, where the second party is trusted and the output is determined by a separate binding commitment, is fine. SIGHASH_ALL inside a naive multi-party protocol where one assembler constructs the final transaction and the others cannot verify it is, in practice, the dangerous configuration. The flag does not determine safety. The protocol surrounding it does.

So if you find a SIGHASH_NONE in a transaction you are auditing: do not panic immediately. Ask what protocol generated it and what guarantees surround the output construction. That is the professionally correct question, and the answer will tell you far more than the flag value alone.

Why This Architecture Aged Well

The elegance here is the separation of authorisation from assembly. A signer commits to exactly what they care about, signs offline, hands the signature to an assembler, and trusts cryptography rather than the assembler's good intentions. That is a meaningful distinction in adversarial environments.

It is why Lightning Network payment channels, CoinJoin implementations, and PSBT (Partially Signed Bitcoin Transactions, defined in BIP174) all depend on sighash semantics. PSBT is essentially a standardised envelope for routing a partially-signed transaction among wallets and hardware signers, each party adding its signature to its own input until the transaction is complete enough to broadcast. The whole workflow is sighash flags made practical and portable.

One byte, appended to a signature, carrying an instruction about scope. It is about as unassuming as a field in a legal filing's header, and about as consequential once a dispute arises.

The design space that byte opens is still being mapped, more than a decade after the original code shipped.