TeachMeBitcoin

Crowdfunding Protocol Overview

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

24. SIGHASH_ALL vs SIGHASH_ANYONECANPAY in Crowdfunding

The Crowdfunding Challenge in Bitcoin

Traditional Bitcoin transactions require fully formed inputs and outputs before any signing can occur. This makes it difficult to implement "all-or-nothing" crowdfunding where:

How SIGHASH_ANYONECANPAY Enables Crowdfunding

SIGHASH_ALL | SIGHASH_ANYONECANPAY (0x81) creates signatures that:

  1. Commit to all outputs (ensuring the campaign target is respected)

  2. Only sign the contributor's own input (allowing others to add their inputs)

# Crowdfunding Protocol Overview

Step 1: Campaign creator defines the goal

Goal: Raise 5 BTC for Project X
  Target output: 5 BTC → <project_pubkey>

Step 2: Each contributor creates a partially-signed transaction

Transaction structure:
    Input:  <contributor_utxo>  (e.g., 0.5 BTC)
    Output: 5 BTC → <project_address>

  Signed with SIGHASH_ALL | SIGHASH_ANYONECANPAY
  → Signature commits to: this input + ALL outputs (the 5 BTC output)
  → Does NOT commit to: other contributors' inputs

Step 3: Contributions are collected off-chain

Coordinator gathers partially-signed transactions

Step 4: Assembly (when goal is met)

Coordinator combines all signed inputs into one transaction:
  Input 0: Contributor A (0.5 BTC, already signed)
  Input 1: Contributor B (1.0 BTC, already signed)
  Input 2: Contributor C (1.5 BTC, already signed)
  Input 3: Contributor D (2.0 BTC, already signed)
  Output:  5 BTC → <project_address>

  All signatures remain valid! (each only signed their own input)

Step 5: Broadcast

The assembled transaction is broadcast.
  All 4 contributors' funds move simultaneously.

Why SIGHASH_ALL (without ANYONECANPAY) Fails for Crowdfunding

# Attempt with SIGHASH_ALL:
Contributor A signs with SIGHASH_ALL:
  Commits to Input 0 (their utxo) AND all outputs AND all other inputs

Problem: There are no "other inputs" yet!
  → If contributor B later adds their input,
    contributor A's signature becomes INVALID
    (it committed to zero other inputs, but now there's one)
  → The transaction can never be assembled

The SIGHASH_ALL | SIGHASH_ANYONECANPAY Mechanism

def create_crowdfunding_contribution(private_key, utxo, target_output):
    """
    Create a signed crowdfunding contribution using SIGHASH_ALL|ANYONECANPAY.
    """
    # Build a skeleton transaction with just our input and the target output
    tx = Transaction(
        inputs=[Input(outpoint=utxo.outpoint, sequence=0xFFFFFFFF)],
        outputs=[target_output]  # The campaign goal output
    )

    sighash_type = SIGHASH_ALL | SIGHASH_ANYONECANPAY  # 0x81

    # Compute the sighash
    # ANYONECANPAY means: only serialize THIS input, not "all inputs"
    z = compute_sighash(tx, input_index=0, sighash_type=sighash_type)

    # Sign
    r, s = ecdsa_sign(private_key, z)
    normalize_low_s(r, s)
    sig = encode_der(r, s) + bytes([sighash_type])

    return sig, utxo.script_pubkey

Assemble and Verify

def assemble_crowdfunding_tx(contributions, target_output):
    """
    Combine individually-signed contributions into a final transaction.
    """
    inputs = []
    for (sig, pubkey_script, utxo) in contributions:
        inp = Input(outpoint=utxo.outpoint)
        inp.script_sig = push(sig) + push(pubkey_script)
        inputs.append(inp)

    tx = Transaction(
        inputs=inputs,
        outputs=[target_output]
    )

    # All existing signatures remain valid because:
    # Each signature used ANYONECANPAY → only committed to its own input
    # Each signature used ALL → committed to ALL outputs → target_output is the same
    return tx

Comparison Table

| Feature | SIGHASH_ALL | SIGHASH_ALL|ANYONECANPAY | |

☕ 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!