Step 5: Calculate Preimage and Sighash
Now that we have our transaction digest and scriptCode, we're ready for the signing process.
Before we create our signature, we need to understand two key concepts:
- Preimage
- Sighash (also called commitment hash)
The signing process follows these equations:
1 preimage = version + hashPrevouts + hashSequence + outpoint + scriptCode + value + sequence + hashOutputs + locktime + sighash_type
2 sigHash = sha256(sha256(preimage))
About SIGHASH_TYPE
The sighash_type determines which parts of the transaction are committed to in the signature:
The preimage
is what we actually sign, it's a commitment to all the transaction data we want to protect.
By double-hashing (SHA256d) this preimage, we get our sighash
, which is what gets signed with our private key.
Code Implementation
def get_commitment_hash(
outpoint: bytes, # The input being signed (txid + vout)
scriptcode: bytes, # From step 2
value: int, # Value of the output being spent
outputs: List[bytes], # Transaction outputs
all_inputs: List[bytes] # All transaction inputs (required for BIP143)
) -> bytes:
"""Calculate BIP143 sighash"""
# Version (4 bytes little-endian)
version = int_to_little_endian(1, 4)
# Get transaction digest components
hash_prevouts, hash_sequence, hash_outputs = get_transaction_digest(
all_inputs, # Uses ALL transaction inputs
outputs
)
# Value of spent output (8 bytes little-endian)
value_bytes = int_to_little_endian(value, 8)
# Sequence for THIS input (4 bytes)
sequence = b'\xff\xff\xff\xff' # From test vector
# Locktime (4 bytes little-endian)
locktime = int_to_little_endian(0x11, 4) # 17 in hex
# SIGHASH_ALL (4 bytes little-endian)
sighash_type = int_to_little_endian(1, 4)
# Build preimage according to BIP143 structure
preimage = (
version +
hash_prevouts +
hash_sequence +
outpoint +
scriptcode +
value_bytes +
sequence +
hash_outputs +
locktime +
sighash_type
)
# Double SHA256 to produce the final sighash
return hashlib.sha256(hashlib.sha256(preimage).digest()).digest()
Test Vector from BIP143
Let's verify again our implementation against the official BIP143 test vectors.
You can verify that the values we generated in the previous step match these test vectors from BIP143.
# Test vector values from BIP143
preimage = "0100000096b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd3752b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3bef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a010000001976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac0046c32300000000ffffffff863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e51100000001000000"
# Individual components
nVersion = "01000000"
hashPrevouts = "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
hashSequence = "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
outpoint = "ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a01000000"
scriptCode = "1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac"
amount = "0046c32300000000"
nSequence = "ffffffff"
hashOutputs = "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
nLockTime = "11000000"
nHashType = "01000000"
# Final signature hash
sigHash = "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670"
Next Step
With our sighash ready, we'll move on to sign it.