Signature Hash Flags

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

  1. A starting byte of hex value [0x30]
  2. Length of the signature sequence [0x44] or [0x45]
  3. r-marker byte of hex value 0x02
  4. Length of r [0x21]|| Big-endian representation of r
  5. s-marker byte of hex value 0x02
  6. Length of s [0x20]|| Big-endian representation of s
  7. 1-byte SIGHASH suffix*
Figure 1: Anatomy of a DER signature

Types and application of signature hash flags

Figure 2: SIGHASH types

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

  1. Creating a copy of the transaction,
  2. 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)
  3. Make sure that no other fields are set to empty before the transaction is serialized (Tx_ser).
  4. The flag 0x01 is added to the end of the serialized transaction and passed through a hashing function.
  5. This message is then signed by the signing algorithm to generate the signature.
Equation 1: Hashing function for SIGHASH ALL transaction
Equation 2: Signing algorithm

where e is the signer’s private key and S(r,s) the signature.

Figure 3: SIGHASH ALL

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:

  1. Create a copy of the transaction
  2. Empty each script_sig for all inputs and replace with the script_pubkey they reference
  3. Empty out all output fields
  4. Serialize the transaction
  5. Append 0x02 to Tx_ser, hash, and then sign
Equation 3: Hashing function for SIGHASH NONE transaction

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.

Figure 4: SIGHASH NONE

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).

  1. Create a copy of the transaction
  2. Empty script_sigs for each input and replace with the script_pubkey they reference
  3. Empty out all output fields bar the specific output
  4. Serialize the transaction
  5. Append 0x03 to Tx_ser, hash, and then sign

A change to the specified output or to any of the inputs invalidates the signature.

Figure 5: SIGHASH SINGLE

Modifier Flag

Figure 6: ANYONECANPAY modifier

With ANYONECANPAY set for ALL, changes can be made to all inputs except the select input (index 0) and the outputs (see image below).

Figure 7: ALL|ANYONECANPAY

ANYONECANPAY set for NONE means that changes can be made to all outputs, and inputs except the current input.

Figure 8: NONE|ANYONECANPAY

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.

Figure 9: SINGLE|ANYONECANPAY

Scenarios

Table 1: Use cases for SIGHASH flags

Conclusion

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.

Note:

  1. The || symbol is used to indicate concatenation
  2. * 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.

References

  1. Song, J. (2019). Programming bitcoin: Learn how to program bitcoin from scratch
  2. Rosenbaum, K. (2019). Grokking Bitcoin

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
ochekliye enigbe

Mechanical engineer. Software Developer. Exploring bitcoin software development at Qala.