TeachMeBitcoin

Proof of key ownership without spending

From TeachMeBitcoin, the free encyclopedia Reading time: 2 min

12. SIGHASH_NONE — Signing Inputs Only

Overview

SIGHASH_NONE (value 0x02) commits to all inputs but signs no outputs. A signature with SIGHASH_NONE says: "I authorize spending my input, but I don't care where the funds go."

Commits to:
✓ All inputs (their outpoints)
✓ Input sequences (for current input; others set to 0)

Does NOT commit to:
✗ Any outputs (completely blank)
✗ Other inputs' sequences

How SIGHASH_NONE Modifies the Transaction Copy

def apply_sighash_none(tx_copy, input_index):
    # Remove ALL outputs
    tx_copy.outputs = []

    # Set all other inputs' sequences to 0
    for i, inp in enumerate(tx_copy.inputs):
        if i != input_index:
            inp.sequence = 0

    # Current input's sequence is preserved
    return tx_copy

Security Implications

SIGHASH_NONE is extremely dangerous when used naively:

Scenario: Alice creates a SIGHASH_NONE signature for her input.
She intends to send to Bob.

Risk: Anyone who sees this signature can:

1. Take Alice's signed input

2. Create a new transaction with the SAME input but DIFFERENT outputs

3. Send Alice's funds anywhere they want

Alice has signed a "blank check" — she authorized the spend
but left the destination empty for anyone to fill in.

Legitimate Uses of SIGHASH_NONE

Despite the danger, there are legitimate protocols that leverage this behavior:

1. Signaling Without Spending

A party can demonstrate they have signing capability for an input without committing to any specific transaction:

# Proof of key ownership without spending
sighash_none_sig = sign(private_key, sighash_none_preimage)
# Broadcasting this would let miners steal funds, but it proves key ownership

2. Multi-Party Protocols with Trusted Coordinators

In some CoinJoin variants, participants sign with SIGHASH_NONE and trust a coordinator to fill outputs correctly.

3. Replace-by-Fee with Empty Outputs (Historical)

Early RBF experiments used SIGHASH_NONE to indicate inputs that could be repackaged.

Example Transaction Construction

# Creating a SIGHASH_NONE signature (dangerous — educational purposes only)
def sign_sighash_none(private_key, tx, input_index, script_code):
    # Modified tx: no outputs, other sequences zeroed
    tx_copy = copy_transaction(tx)
    tx_copy.outputs.clear()
    for i in range(len(tx_copy.inputs)):
        if i != input_index:
            tx_copy.inputs[i].sequence = 0
    tx_copy.inputs[input_index].script = script_code
    for i in range(len(tx_copy.inputs)):
        if i != input_index:
            tx_copy.inputs[i].script = b''

    preimage = tx_copy.serialize() + struct.pack('<I', SIGHASH_NONE)
    z = double_sha256(preimage)
    der_sig = ecdsa_sign_der(private_key, z)
    return der_sig + bytes([SIGHASH_NONE])
☕ Help support TeachMeBitcoin

TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!