BIP-143-like SigHashes for Kaspa
This document outlines a change to the Kaspa protocol similar to
Bitcoin's BIP-143 proposal.
The protocol outlined here is very similar to Bitcoin's proposal,
with slight variations due to different transaction structure in Kaspa,
and the use of Blake2b hash (as opposed to SHA256 in bitcoin).
For motivation and further details see the original BIP-143 proposal: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
Specification
SigHashTypes
The SigHashTypes are defined as follows:
SigHashAll SigHashType = 0b00000001
SigHashNone SigHashType = 0b00000010
SigHashSingle SigHashType = 0b00000100
SigHashAnyOneCanPay SigHashType = 0b10000000
Note this is different from bitcoin where SigHashSingle has the value 0b00000011. This was changed to make SigHashType a true bit-field. In addition, SigHashType is always serialized as a single byte, whilst in bitcoin it is often serialized as a 4-byte uint, and only 1-byte in the signature itself.
SigHash calculation
A new transaction digest algorithm is defined:
Blake2b of the serialization of:
1. tx.Version (2-bytes unsigned little endian)
2. previousOutputsHash (32-byte hash)
3. sequencesHash (32-byte hash)
4. sigOpCountsHash (32-byte has)
5. txIn.PreviousOutpoint.TransactionID (32-byte hash)
6. txIn.PreviousOutpoint.Index (4-bytes unsigned little endian)
7. txIn.PreviousOutput.ScriptPubKeyVersion (2-bytes unsigned little endian)
8. txIn.PreviousOutput.ScriptPubKey.length (8-bytes unsigned little endian)
9. txIn.PreviousOutput.ScriptPubKey (serialized as script)
10. txIn.PreviousOutput.Value (8-bytes unsigned little endian)
11. txIn.Sequence (8-bytes unsigned little endian)
12. txIn.SigOpCount (1-byte unsigned little endian)
13. outputsHash (32-byte hash)
14. tx.Locktime (8-bytes unsigned little endian)
15. tx.SubnetworkID (20-byte hash)
16. tx.Gas (8-bytes unsigned little endian)
17. payloadHash (32-byte hash)
18. SigHash type of the signature (1-byte unsigned little endian)
(Note: SigHash type is different from bitcoin where it's 4-bytes)
Where:
tx - the transaction signed
txIn - the transaction input signed
Semantics
The semantics of the original sighash types remain unchanged, except the followings:
- The way of serialization is changed;
- All sighash types commit to the amount being spent by the signed input
- SINGLE does not commit to the input index. When ANYONECANPAY is not set, the semantics are unchanged since previousOutputsHash and txIn.PreviousOutpoint.* together implictly commit to the input index. When SINGLE is used with ANYONECANPAY, omission of the index commitment allows permutation of the input-output pairs, as long as each pair is located at an equivalent index
The semantics of most values are straightforward, except the following:
previousOutputsHash
- If ANYONECANPAY flag is set, then previousOutputsHash is a uint256 of 0x0000......0000
- Otherwise previousOutputsHash is the Blake2b hash of the
serialization of all input outpoints in the following format:
1. previousOutpoint.TransactionId 2. previousOutpoint.Index
sigOpCountsHash
- If ANYONECANPAY flag is set, then previousOutputsHash is a uint256 of 0x0000......0000
- Otherwise, sigOpCountsHash is the Blake2b hash of the serialization of the SigOpCount of all inputs
sequencesHash
- If ANYONECANPAY, SINGLE or NONE sighash type is set, then sequencesHash is a uint256 of 0x0000......0000
- Otherwise, sequencesHash is the Blake2b hash of the serialization of the Sequence of all inputs
outputsHash
- If the sighashType SINGLE and the input index is larger or equal to the number of inputs or the sighashType is NONE, then outputs hash is a uint256 of 0x0000......0000
- If sighashType is SINGLE and the input index is smaller then the number of outputs, then outputsHash is the Blake2b hash of the following format for the output with the same index as the input.
- Otherwise, outputsHash is the Blake2b hash of the following format for all outputs.
1. Value
2. ScriptPublicKey.Version
3. ScriptPublicKey.Script
payloadHash
- If the tx is a native transaction (a.k.a. SubnetworkID = 0x0000......0000), then payloadHash is a uint256 of 0x0000......000
- Otherwise payloadHash is the Blake2b hash of the transaction's Payload