Step 7: Add Witness Field

Our transaction now has all its fields populated except for the witness data.

SVG Image

For a P2WPKH input, the witness structure is:

text
1   
2    witness = [num_items] [signature_item] [pubkey_item]
3
4    where:
5       - num_items = 0x02 (always 2 items for P2WPKH)
6       - signature_item = [length][DER_signature + SIGHASH_ALL]
7       - pubkey_item = [length][compressed_pubkey]

Our test transaction's witness data:

text
   witness = 02                                      # number of witness items
             47                                      # signature length (71 bytes)
             304402203609e17b84f6a7d30c80bfa...01    # DER signature + SIGHASH_ALL
             21                                      # pubkey length (33 bytes)
             025476c2e83188368da1ff3e292e7aca...57   # compressed public key

Code Implementation

python
def get_p2wpkh_witness(priv: bytes, msg: bytes) -> bytes:
    """
    Create witness stack for P2WPKH input with format:
    [num_items][sig_len][signature][pubkey_len][pubkey]
    """
    # Get signature with sighash byte
    signature_with_sighash = sign(priv, msg)
    
    # Get compressed public key
    compressed_public_key = get_pub_from_priv(priv)
    
    # Number of witness items (always 2 for P2WPKH)
    num_witness_items = bytes([2])
    
    # Serialize signature with its length
    sig_len = bytes([len(signature_with_sighash)])
    serialized_sig = sig_len + signature_with_sighash
    
    # Serialize public key with its length
    pk_len = bytes([len(compressed_public_key)])
    serialized_pk = pk_len + compressed_public_key
    
    # Combine all parts
    serialized_witness = num_witness_items + serialized_sig + serialized_pk
    return serialized_witness

BIP143 Test Vector

python
def test_witness_stack():
    # Private key from BIP143
    privkey = bytes.fromhex(
        '619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9'
    )
    
    # Commitment hash from previous step
    commitment = bytes.fromhex(
        'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670'
    )
    
    # Generate witness stack
    witness = get_p2wpkh_witness(privkey, commitment)
    
    # Expected witness data from BIP143 (broken down for clarity)
    expected_witness = (
        b'\x02' +                    # Number of witness items
        b'\x47' +                    # Signature length (71 bytes)
        bytes.fromhex(                # DER signature + SIGHASH_ALL
            '304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a' +
            '0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01'
        ) +
        b'\x21' +                    # Public key length (33 bytes)
        bytes.fromhex(                # Compressed public key
            '025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357'
        )
    )
    
    print("Generated witness:", witness.hex())
    print("Expected witness:", expected_witness.hex())
    assert witness == expected_witness, "Witness stack does not match BIP143 test vector"
    print("Success! Witness stack matches BIP143 test vector")

When you run this code locally, it will generate the witness stack that matches the BIP143 test vector:

python
# Expected witness stack from BIP143
witness = "02" +                    # Number of witness items
         "47" +                    # Signature length (71 bytes)
         "304402203609e17b84f6a7d30c80bfa...01   # DER signature + SIGHASH_ALL
         21                                      # pubkey length (33 bytes)
         025476c2e83188368da1ff3e292e7aca...57   # compressed public key

Note about Browser Execution

This code cannot be run directly in the browser as Trinket doesn't support the ECDSA module. Please run the code locally to verify the witness stack generation. Here's what you should see when running locally:

SVG Image
Suggest Edits
View our public visitor count
Built with 🧡 by the Bitcoin Dev Project
We'd love to hear your feedback on this project?Give Feedback