Skip to content

BIP143 - Transaction Signature Verification for Version 0 Witness Programs

BIP143 (Bitcoin Improvement Proposal 143) is one of the Bitcoin improvement proposals, put forward by Johnson Lau and Pieter Wuille in 2016. It defines the signature hash algorithm for Segregated Witness (SegWit) transactions. This proposal addresses several security and performance issues of the traditional signature verification algorithm and is an important complement to BIP141 (Segregated Witness).

Core Concept

Before BIP143, the signature hash algorithm used by Bitcoin had several serious problems, particularly the quadratic hashing problem (O(n^2) complexity) and security risks for hardware wallets. BIP143 designed an entirely new signature hash algorithm for SegWit transactions, fundamentally solving these problems.

BIP143 only applies to version 0 witness programs, including P2WPKH (Pay to Witness Public Key Hash) and P2WSH (Pay to Witness Script Hash). This new algorithm not only improves performance but also enhances security, especially for hardware wallet users.

Problems with the Old Algorithm

1. Quadratic Hashing Problem (O(n^2) Complexity)

The traditional SIGHASH algorithm had performance issues when verifying transactions:

Problem Description: - Each input's signature verification required hashing the entire transaction - For a transaction with N inputs, N complete transaction hashes were needed - Each hash had to process all N inputs - Total complexity was O(N^2)

Practical Impact:

1 input transaction: 1 hash
10 input transaction: 10 hashes x 10 inputs = 100 operations
100 input transaction: 100 hashes x 100 inputs = 10,000 operations

Attack Vector: - Maliciously constructed large transactions (hundreds or thousands of inputs) - Caused exponential growth in node verification time - Could result in denial-of-service attacks - In 2015, attack transactions requiring over 1 minute to verify were observed

2. Hardware Wallet Security Issues

The traditional algorithm was unfriendly to hardware wallets:

Unable to Verify Input Amounts During Signing: - The signature hash did not include the input amount - Hardware wallets could not independently verify input amounts - A malicious host could misrepresent input amounts - Users could unknowingly sign transactions that sent most of their funds as fees

Example:

Actual situation:
  Input: 10 BTC
  Output: 0.1 BTC (recipient) + 9.9 BTC (change)
  Fee: 0 BTC

Malicious host tells the hardware wallet:
  Input: 0.2 BTC
  Output: 0.1 BTC (recipient) + 0.09 BTC (change)
  Fee: 0.01 BTC

Hardware wallet displays to user: Fee 0.01 BTC (appears reasonable)
Actual fee: 10 - 0.1 - 9.9 = 0 BTC (or worse, if the change address is replaced)

After the user signs:
  The real fee could be as high as 9.9 BTC (if the malicious host removes the change output)

3. Offline Signing Difficulty

The traditional algorithm required complete transaction data: - Hardware wallets needed to receive the complete transaction data for all inputs - Large data transfer volumes and complex verification - Increased attack surface and user operation complexity

BIP143 Solution

Signature Hash Algorithm Improvements

BIP143 introduced a new signature hash calculation method:

New Algorithm Features: 1. Linear complexity (O(n)): Each hash operation is performed only once 2. Commits to input amounts: The signature includes the input amount 3. Cache-friendly: Common hash values can be precomputed 4. Hardware wallet secure: All critical information can be independently verified

Signature Hash Structure

Signature hash = SHA256(SHA256(
  1. nVersion                      (4 bytes)
  2. hashPrevouts                  (32 bytes)
  3. hashSequence                  (32 bytes)
  4. outpoint                      (36 bytes)
  5. scriptCode                    (variable length)
  6. value                         (8 bytes) <- New!
  7. nSequence                     (4 bytes)
  8. hashOutputs                   (32 bytes)
  9. nLocktime                     (4 bytes)
  10. nHashType                    (4 bytes)
))

Key Field Details

1. nVersion

Transaction version number (4 bytes)

2. hashPrevouts

Hash of all input outpoints:

hashPrevouts = SHA256(SHA256(all input outpoints))

outpoint = txid (32 bytes) + vout (4 bytes)

Advantage: - Computed only once and can be cached - All inputs share the same hash value - Reduces complexity from O(n^2) to O(n)

3. hashSequence

Hash of all input sequence numbers:

hashSequence = SHA256(SHA256(all input nSequence values))

Purpose: - Commits to all inputs' nSequence values - Prevents selective signing attacks - Supports BIP68 relative time-locks

4. outpoint

The current input's outpoint (36 bytes):

outpoint = txid (32 bytes) + vout (4 bytes)

5. scriptCode

Script code (variable length):

For P2WPKH:

scriptCode = 0x1976a914{20-byte public key hash}88ac
Equivalent to a P2PKH script: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

For P2WSH:

scriptCode = witnessScript

6. value

Input amount (8 bytes) <- The most important improvement!

value = the amount of the UTXO being spent by this input (in satoshis)

Security Significance: - Explicitly commits to the input amount during signing - Hardware wallets can independently verify this - Prevents malicious hosts from misrepresenting amounts - Users can accurately calculate fees

7. nSequence

Current input's sequence number (4 bytes)

8. hashOutputs

Hash of all outputs:

hashOutputs = SHA256(SHA256(all outputs))

Each output = value (8 bytes) + scriptPubKey (variable length)

Advantage: - Computed only once - Commits to all outputs - Hardware wallets can verify outputs one by one before signing

9. nLocktime

Transaction locktime (4 bytes)

10. nHashType

Signature hash type (4 bytes)

Technical Advantages

1. Performance Optimization

Old Algorithm:

For a transaction with N inputs:
- Each input signature requires hashing the entire transaction
- Total hash operations: O(N^2)
- Large transaction verification time: exponential growth

New Algorithm (BIP143):

For a transaction with N inputs:
- hashPrevouts: computed 1 time, shared by all inputs
- hashSequence: computed 1 time, shared by all inputs
- hashOutputs: computed 1 time, shared by all inputs
- Each input only needs to hash about 200 bytes of data
- Total hash operations: O(N)

Practical Comparison:

100 input transaction:
- Old algorithm: ~10,000 hash operations (assuming 1KB per input)
- New algorithm: ~103 hash operations (3 common hashes + 100 inputs)
- Speed improvement: approximately 100x

2. Hardware Wallet Security

Input Amount Verification:

Signing flow:
1. Host sends: UTXO amount
2. Hardware wallet computes signature hash (includes amount)
3. Amount is included in the signature
4. If the host misrepresents the amount, the signature will be invalid

Output Verification:

Signing flow:
1. Host sends outputs one by one
2. Hardware wallet displays each output for user confirmation
3. Hardware wallet computes hashOutputs
4. hashOutputs is included in the signature
5. If any output is modified, the signature will be invalid

Fee Calculation:

Hardware wallet can safely compute:
  Total inputs = sum(input amounts)  <- included in signature
  Total outputs = sum(output amounts) <- included in signature
  Fee = Total inputs - Total outputs

Displayed to user: accurate fee

3. Offline Signing Optimization

Minimal Data Requirements: Hardware wallets only need: - Current input's UTXO information (txid, vout, amount, script) - List of all outputs - hashPrevouts, hashSequence (can be precomputed or provided by host)

No Complete Transaction History Required: - Does not need complete preceding transactions for all inputs - Reduces data transfer volume - Simplifies user operation

SIGHASH Type Support

BIP143 supports all traditional SIGHASH types:

SIGHASH_ALL (0x01)

Signs all inputs and outputs:

hashPrevouts = SHA256(SHA256(all outpoints))
hashSequence = SHA256(SHA256(all nSequence values))
hashOutputs = SHA256(SHA256(all outputs))

SIGHASH_NONE (0x02)

Signs all inputs but no outputs:

hashPrevouts = SHA256(SHA256(all outpoints))
hashSequence = 0x0000...0000 (32 zeros)
hashOutputs = 0x0000...0000 (32 zeros)

SIGHASH_SINGLE (0x03)

Signs all inputs and the output at the corresponding index:

hashPrevouts = SHA256(SHA256(all outpoints))
hashSequence = 0x0000...0000 (32 zeros)
hashOutputs = SHA256(SHA256(output at corresponding index))

SIGHASH_ANYONECANPAY (0x80)

Can be combined with the above types, signs only the current input:

hashPrevouts = 0x0000...0000 (32 zeros)
hashSequence = 0x0000...0000 (32 zeros)
hashOutputs = depends on the combined SIGHASH type

Practical Applications

Hardware Wallets (Ledger, Trezor, etc.)

Secure Signing Flow: 1. User initiates a transaction on the hardware wallet 2. Host application builds the transaction and sends it to the hardware wallet 3. Hardware wallet displays each output address and amount, requesting user confirmation 4. Hardware wallet calculates and displays the total fee 5. After user confirmation, the hardware wallet signs (amounts and outputs are included in the signature) 6. Even if the host application is malicious, it cannot modify the transaction after user confirmation

Batch Payments

Optimized Signing Performance: - Exchanges or payment service providers need to process transactions with many outputs - For example: 1 input + 1000 outputs (batch payroll) - BIP143 makes signing and verification of such transactions faster - Nodes can quickly verify large batch payment transactions

Lightning Network

Commitment Transaction Security: - Lightning Network commitment transactions may have multiple inputs - BIP143 ensures efficient signature verification - Committing to input amounts enhances channel security

Relationship with Other BIPs

BIP141 (Segregated Witness)

BIP143 is a companion proposal to BIP141: - BIP141 defines the structure of witness data - BIP143 defines the signature algorithm for witness transactions - Together they form the complete SegWit implementation

BIP144 (Peer-to-Peer Services)

BIP144 defines the network transmission format: - Transmits witness data between nodes - BIP143 signature verification occurs on the receiving end

BIP341 (Taproot)

Taproot uses a different signature algorithm: - Taproot uses BIP340 (Schnorr signatures) - But the signature hash algorithm draws on BIP143's design - Similarly commits to input amounts with linear complexity

Security Considerations

1. Input Amount Verification

Hardware wallet implementations must: - Independently obtain and verify UTXO amounts - Verify amounts before computing the signature hash - Display accurate fees to the user

2. Output Hash Verification

All outputs must be verified: - Display output addresses and amounts to the user one by one - Compute hashOutputs after user confirmation - Ensure hashOutputs is not modified after signing

3. Replay Protection

Although BIP143 itself does not provide replay protection: - Committing to input amounts makes cross-chain replay attacks more difficult - Combined with other mechanisms (such as different coin types), replay can be prevented

Implementation Details

Pseudocode Example

def SignatureHash(scriptCode, txTo, inIdx, hashType, value):
    """
    Compute the BIP143 signature hash

    Parameters:
    - scriptCode: Script code
    - txTo: Transaction to sign
    - inIdx: Current input index
    - hashType: Signature hash type
    - value: Input amount (satoshis)
    """

    # 1. nVersion
    hashPrevouts = b'\x00' * 32
    hashSequence = b'\x00' * 32
    hashOutputs = b'\x00' * 32

    # 2. hashPrevouts
    if not (hashType & SIGHASH_ANYONECANPAY):
        hashPrevouts = GetHashPrevouts(txTo)

    # 3. hashSequence
    if (not (hashType & SIGHASH_ANYONECANPAY) and
        (hashType & 0x1f) != SIGHASH_SINGLE and
        (hashType & 0x1f) != SIGHASH_NONE):
        hashSequence = GetHashSequence(txTo)

    # 4. hashOutputs
    if (hashType & 0x1f) not in [SIGHASH_SINGLE, SIGHASH_NONE]:
        hashOutputs = GetHashOutputs(txTo)
    elif ((hashType & 0x1f) == SIGHASH_SINGLE and
          inIdx < len(txTo.vout)):
        hashOutputs = SHA256(SHA256(txTo.vout[inIdx].serialize()))

    # Build the signature hash preimage
    ss = b''
    ss += struct.pack('<I', txTo.nVersion)
    ss += hashPrevouts
    ss += hashSequence
    ss += txTo.vin[inIdx].prevout.serialize()
    ss += SerializeScriptCode(scriptCode)
    ss += struct.pack('<Q', value)  # Input amount
    ss += struct.pack('<I', txTo.vin[inIdx].nSequence)
    ss += hashOutputs
    ss += struct.pack('<I', txTo.nLockTime)
    ss += struct.pack('<I', hashType)

    return SHA256(SHA256(ss))


def GetHashPrevouts(tx):
    """Compute hash of all input outpoints"""
    ss = b''
    for inp in tx.vin:
        ss += inp.prevout.serialize()
    return SHA256(SHA256(ss))


def GetHashSequence(tx):
    """Compute hash of all input sequence numbers"""
    ss = b''
    for inp in tx.vin:
        ss += struct.pack('<I', inp.nSequence)
    return SHA256(SHA256(ss))


def GetHashOutputs(tx):
    """Compute hash of all outputs"""
    ss = b''
    for out in tx.vout:
        ss += out.serialize()
    return SHA256(SHA256(ss))

Comparison: Before and After BIP143

Feature Traditional SIGHASH BIP143
Complexity O(n^2) O(n)
Large Transaction Verification Slow (could exceed 1 minute) Fast (seconds)
Input Amount Commitment No Yes
Hardware Wallet Security Cannot independently verify Can independently verify
Cache Optimization Not supported Supported
DoS Attack Risk High Low
Data Transfer Volume (hardware wallet) Large (needs complete transaction) Small (only key data needed)

Practical Impact

Impact on Users

Hardware Wallet Users: - More secure: Can accurately verify fees - Faster: Improved signing speed - Simpler: Reduced data transfer volume

Regular Users: - Faster transaction confirmations (faster node verification) - Reduced network congestion risk - Support for more complex transaction types

Impact on Developers

Wallet Development: - Requires implementing the new signature algorithm - Hardware wallets can provide a better user experience - Simplifies offline signing implementation

Node Software: - Significantly improved verification performance - Enhanced resistance to DoS attacks - Support for larger batch transactions

Impact on the Network

Performance Improvements: - Faster block verification - Can safely process larger transactions - Reduced hardware requirements for verification nodes

Security Enhancements: - Eliminated the quadratic hashing attack vector - Improved hardware wallet security - Reduced signature-related security vulnerabilities

Activation and Deployment

Soft Fork Activation

BIP143 was activated as part of the SegWit upgrade in August 2017: - Activation method: BIP9 version bit 1 - Activation height: 481,824 (August 24, 2017) - Activated simultaneously with BIP141 - Backward compatible: Old nodes treat SegWit transactions as "anyone-can-spend"

Compatibility

New and Old Transaction Types: - Legacy transactions (non-SegWit): Continue using the old SIGHASH algorithm - SegWit v0 transactions (P2WPKH, P2WSH): Use the BIP143 algorithm - SegWit v1 transactions (Taproot): Use the new algorithm defined in BIP341

Wallet Support: All major wallets have implemented BIP143: - Hardware wallets: Ledger, Trezor, Coldcard fully support it - Software wallets: Bitcoin Core, Electrum, Wasabi, etc. - Enterprise solutions: BitGo, Coinbase, etc.

Future Development

Lessons Applied to Taproot

BIP341 (Taproot) signature hash algorithm: - Draws on BIP143's design principles - Similarly commits to input amounts - Similarly uses O(n) complexity - Further optimized and extended

Batch Verification

Further optimizations based on BIP143: - Batch verification of Schnorr signatures - Cross-input signature aggregation - More efficient block verification

Summary

BIP143 brought significant performance and security improvements to Segregated Witness transactions through an improved signature hash algorithm:

Core Improvements: - Performance: Reduced from O(n^2) to O(n), eliminating the quadratic hashing problem - Security: Commits to input amounts, protecting hardware wallet users - Efficiency: Supports caching, optimizing signing and verification speed - Simplification: Reduces data requirements for offline signing

Practical Value: - Eliminated the DoS attack vector based on large transactions - Enabled hardware wallets to safely display accurate fees - Improved node capability to verify large transactions - Laid the foundation for subsequent upgrades like Taproot

Although BIP143 is a highly technical proposal, its impact is far-reaching. It not only solved long-standing performance and security problems but also provided a solid foundation for the expansion and secure use of the Bitcoin network. For hardware wallet users, BIP143 is a key technology for protecting funds; for the Bitcoin network, it is an important upgrade for resisting attacks and improving performance.