A digital signature is a “mathematical scheme for demonstrating the authenticity of a message” (Antonopoulos, 2017). It finds use in bitcoin transactions where it proves that transactions have been created by “known” senders, that “known” senders cannot repudiate broadcast transactions, and that the transactions have not been changed from source to destination(s). Signatures are created by passing the transaction (or parts of it) through a hashing function and subsequently through a signing function that uses the owner’s private key.
Signatures can apply to all or parts of a transaction and the way we can tell is by inspecting the signature hash flags. These flags are 8-bit long characters appended to the end of a signature and are important because they make it possible for transactions to be constructed in different ways. The simplest type of transaction one can construct is a transaction that has just one input, referencing a UTXO, that pays to a single output address. However, transactions can have multiple inputs and outputs, with inputs referencing UTXOs from different owners who may sign their inputs. In this way, a partially constructed transaction can be created, where owners collaborate to collect all the needed signatures to make the otherwise invalid transaction valid. With signature hash (SIGHASH) flags, signatures can indicate what part of the transaction is included in the hash.
This article briefly explains the anatomy of signatures and how to identify SIGHASH flags, the types of SIGHASH flags, how SIGHASH types are applied, as well as scenarios where they can be used.
Anatomy of a DER signature
Digital signatures are serialized using the Distinguished Encoding Rules (DER) which encodes the standards for serializing digital signatures S(r,s). These signatures consist of the following parts, in order:
- A starting byte of hex value [0x30]
- Length of the signature sequence [0x44] or [0x45]
- r-marker byte of hex value 0x02
- Length of r [0x21]|| Big-endian representation of r
- s-marker byte of hex value 0x02
- Length of s [0x20]|| Big-endian representation of s
- 1-byte SIGHASH suffix*
Types and application of signature hash flags
There are three types of signature hash flags: ALL, NONE, and SINGLE. Figure 3 shows the byte representation of each type.
For SIGHASH ALL, given a transaction Tx, the signature applies to all of Tx’s inputs and all its outputs (see green bounding boxes). SIGHASH ALL is applied by
- Creating a copy of the transaction,
- Empty script_sigs for each input and replace with the script_pubkey they reference. This is done because the “signature is part of the script_sig and … can’t sign itself” (Song, 2019, p. 132)
- Make sure that no other fields are set to empty before the transaction is serialized (Tx_ser).
- The flag 0x01 is added to the end of the serialized transaction and passed through a hashing function.
- This message is then signed by the signing algorithm to generate the signature.
where e is the signer’s private key and S(r,s) the signature.
The transaction is rendered invalid if any of its details are changed because the signature will change too and be invalid.
For SIGHASH NONE, the signature applies to all of Tx’s inputs (see green bounding box) but to none of the outputs. The application process is as stated below:
- Create a copy of the transaction
- Empty each script_sig for all inputs and replace with the script_pubkey they reference
- Empty out all output fields
- Serialize the transaction
- Append 0x02 to Tx_ser, hash, and then sign
For SIGHASH NONE, any output can be modified without invalidating the signature, but if any one of the inputs is modified, the signature is rendered invalid.
For SIGHASH SINGLE, all the inputs of the given transaction Tx are signed and one output that has the same index of one of the inputs being signed. This is essentially “authorizing all other inputs to go with a specific output” (Song, 2019, p. 133).
- Create a copy of the transaction
- Empty script_sigs for each input and replace with the script_pubkey they reference
- Empty out all output fields bar the specific output
- Serialize the transaction
- Append 0x03 to Tx_ser, hash, and then sign
A change to the specified output or to any of the inputs invalidates the signature.
An ANYONECANPAY modifier flag exists that can be added to the aforementioned flags that apply to a single input in a transaction. Rosenbaum (2019) considers the ANYONECANPAY modifier flag as a way to commit to inputs only, by setting or not setting it, and the existing SIGHASH types (ALL, NONE, SINGLE) as a way to commit to outputs only.
With ANYONECANPAY set for ALL, changes can be made to all inputs except the select input (index 0) and the outputs (see image below).
ANYONECANPAY set for NONE means that changes can be made to all outputs, and inputs except the current input.
ANYONECANPAY set for SINGLE means that changes can be made to all outputs except the output with a matching index with the current input. All other inputs can be modified, added, and/or removed.
The table below shows a summary of use cases where these flags can be applied
In reviewing the bitcoin fundamentals necessary to explore the lightning network, I went down the rabbit hole of signature hash flags. These flags mark the parts of a transaction that are signed by a signature and provide flexible ways to construct transactions. I explained how to identify these flags from the anatomy of a DER signature, the 6 types of flags (including modifiers) that exist, and how some of these flags are applied to a transaction.
I would deeply appreciate any feedback you can provide. If you found this article helpful/useful or found factual misrepresentation, please do not hesitate to comment or contact me here or on Twitter @engb_os.
- The || symbol is used to indicate concatenation
- * SIGHASH flags should be a byte long although implementation serializes them to 4-bytes. Pieter Wuille provides a possible reason why this is the case here.
- Antonopoulos, A. (2017). Mastering bitcoin: Programming the open blockchain
- Song, J. (2019). Programming bitcoin: Learn how to program bitcoin from scratch
- Rosenbaum, K. (2019). Grokking Bitcoin