Menu
BIP-bip-141 Final

BIP-141: Segregated Witness

SegWit specification. Separating signatures from transaction data for scalability and malleability fixes.

Type Bitcoin Improvement Proposal
Number bip-141
Status Final
Authors Eric Lombrozo, Johnson Lau, Pieter Wuille
Original https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki

BIP-141: Segregated Witness (Consensus Layer)

Segregated Witness (SegWit) is a soft fork that separates signature data (witness) from the transaction structure. Activated in August 2017.

Motivation

Transaction Malleability

Before SegWit, transaction IDs could be changed without invalidating signatures:

  • Signatures could be modified (same key, different encoding)
  • txid changed → dependent transactions broke

Problem for Layer 2: Lightning channels need stable txids.

Scalability

Signature data is ~60% of transaction size. By segregating:

  • More transactions per block
  • Reduced bandwidth for SPV clients

How SegWit Works

Traditional Transaction

┌──────────────────────────────┐
│ Version                      │
│ Input Count                  │
│ Inputs (with scriptSig)      │ ← Signatures here
│ Output Count                 │
│ Outputs                      │
│ Locktime                     │
└──────────────────────────────┘

    txid = hash(all of this)

SegWit Transaction

┌──────────────────────────────┐
│ Version                      │
│ Marker (0x00)                │ ← SegWit flag
│ Flag (0x01)                  │
│ Input Count                  │
│ Inputs (empty scriptSig)     │
│ Output Count                 │
│ Outputs                      │
│ Witness                      │ ← Signatures here (separate)
│ Locktime                     │
└──────────────────────────────┘

    txid = hash(without witness)
    wtxid = hash(with witness)

Witness Programs

Structure

<version byte> <witness program>
VersionLengthType
020 bytesP2WPKH
032 bytesP2WSH
132 bytesP2TR (Taproot)

P2WPKH (Pay-to-Witness-Public-Key-Hash)

scriptPubKey:

OP_0 <20-byte-pubkey-hash>

Witness:

<signature> <public-key>

Equivalent to P2PKH but with witness data.

P2WSH (Pay-to-Witness-Script-Hash)

scriptPubKey:

OP_0 <32-byte-script-hash>

Witness:

<script arguments> <witness script>

Equivalent to P2SH for complex scripts.

Block Weight

SegWit introduces “weight” instead of byte size:

weight = base_size × 3 + total_size
ComponentWeight Factor
Non-witness data4
Witness data1

Max block weight: 4,000,000 WU (effectively ~2-4 MB)

Virtual Size

For fee calculation:

vsize = ⌈weight / 4⌉

Commitment Structure

Witness data is committed in coinbase:

Coinbase output:
OP_RETURN <witness commitment>

Commitment = SHA256(SHA256(witness_root || witness_reserved))

This ensures witness data integrity without changing block header.

Benefits

1. Malleability Fix

txid no longer includes signatures:

  • Stable txids for unconfirmed transactions
  • Enables Lightning Network and other L2

2. Capacity Increase

~1.8x effective capacity for typical transactions.

3. Script Versioning

Witness version byte allows future upgrades:

  • Version 0: P2WPKH, P2WSH
  • Version 1: Taproot (BIP-341)
  • Versions 2-16: Reserved for future

4. Linear Signature Hashing

Fixes quadratic hashing vulnerability:

# Old: O(n²) for n inputs
# SegWit: O(n) via cached midstate

Address Formats

Native SegWit (Bech32)

bc1q... (P2WPKH, 42 chars)
bc1q... (P2WSH, 62 chars)

Wrapped SegWit (P2SH)

For compatibility with old software:

3... (P2SH-P2WPKH)
3... (P2SH-P2WSH)

Implementation

Creating P2WPKH Output

const bitcoin = require('bitcoinjs-lib');

// From public key
const pubkey = Buffer.from('02...', 'hex');
const { address } = bitcoin.payments.p2wpkh({ pubkey });
// bc1q...

Spending P2WPKH

const psbt = new bitcoin.Psbt();

psbt.addInput({
  hash: txid,
  index: vout,
  witnessUtxo: {
    script: Buffer.from('0014...', 'hex'),  // scriptPubKey
    value: 100000
  }
});

psbt.addOutput({
  address: recipient,
  value: 90000
});

psbt.signInput(0, keyPair);
psbt.finalizeAllInputs();

const tx = psbt.extractTransaction();

Signature Hash Algorithm

BIP-143 defines new sighash for SegWit:

hashPrevouts = SHA256(SHA256(all input outpoints))
hashSequence = SHA256(SHA256(all input sequences))
hashOutputs = SHA256(SHA256(all outputs))

preimage =
  nVersion ||
  hashPrevouts ||
  hashSequence ||
  outpoint ||
  scriptCode ||
  amount ||
  nSequence ||
  hashOutputs ||
  nLockTime ||
  sighashType

sighash = SHA256(SHA256(preimage))

Benefits:

  • O(n) complexity instead of O(n²)
  • Commits to input amounts (prevents fee attacks)

Migration Path

From Legacy to SegWit

  1. Generate new SegWit addresses
  2. Move funds when convenient
  3. Use SegWit for all new receiving

Wrapped SegWit

For sending to recipients who don’t support native:

// P2SH-wrapped P2WPKH
const { address } = bitcoin.payments.p2sh({
  redeem: bitcoin.payments.p2wpkh({ pubkey })
});
// 3...

For Agents

Always Use Native SegWit

  • Lower fees than legacy
  • Better than wrapped SegWit
  • Wide support (2024+)

Fee Estimation

// SegWit transaction vsize
const vsize = Math.ceil((
  10 +                    // overhead
  inputs.length * 68 +    // P2WPKH inputs
  outputs.length * 31     // P2WPKH outputs
));

const fee = vsize * feeRate;

Verify SegWit Support

# Check if address is SegWit
if [[ $address == bc1* ]]; then
  echo "Native SegWit"
elif [[ $address == 3* ]]; then
  echo "Could be wrapped SegWit or P2SH"
fi

Machine-Readable Summary

{
  "bip": 141,
  "title": "Segregated Witness",
  "status": "final",
  "activated": "2017-08-24",
  "block_height": 481824,
  "max_block_weight": 4000000,
  "witness_versions": {
    "0": ["p2wpkh", "p2wsh"],
    "1": ["p2tr"]
  },
  "benefits": ["malleability-fix", "capacity-increase", "script-versioning"]
}