Skip to content

Instantly share code, notes, and snippets.

@Kixunil
Last active November 23, 2023 21:30
Show Gist options
  • Save Kixunil/94f829ff2371a4f1224c88bc587addf7 to your computer and use it in GitHub Desktop.
Save Kixunil/94f829ff2371a4f1224c88bc587addf7 to your computer and use it in GitHub Desktop.
SIGHASH_FLEXIBLE: a solution to upgradeable Cross-Input Signature Aggregation

SIGHASH_FLEXIBLE Proposal

A solution to upgradeable Cross-Input Signature Aggregation. (CISA)

Motivation

From what I understood from various conversations one of the major obstacles to CISA is problematic (impossible?) future sighahs changes. Because the contents hashed in signature could become different it would be impossible for old clients to compute the same hash as new clients. It would be possible to just have separate signatures for different versions but that would increase the processing cost and implementation complexity. This document proposes a scriptable approach to the selection of the signed data with an intermediate hash to make future changes possible.

Note that this does not address upgrades via OP_SUCCESS because there are already proposed solutions to this, e.g. just using branches of Taproot MAST instead of OP_IFs and putting signature verification before any other operation.

Summary

The main idea is to only sign annex which contains hash of the data being signed and a script specifying which data is hashed. Signature verification only verifies that the annex is signed and separate consensus rules verify that the data in annex is valid, specifically that the relevant transaction data hash to the specified hash.

Design draft

Create a new sighash flag called SIGHASH_FLEXIBLE. When this sighash is specified only the annex is signed. However new validation rules apply to the annex:

  1. If the annex is shorter than 33 bytes fail - the transaction is invalid.
  2. Create an instance of SHA256 hash engine.
  3. Read compact size script_len from annex[32..]; we call the encoded length of it len_of_compact_script_len.
  4. If script_len > annex.len() - 32 - len_of_compact_script_len fail - the transaction is invalid.
  5. annex[(32 + len_of_compact_script_len)..(32 + len_of_compact_script_len + script_len)] is a special script with following rules:
  6. Opcodes are completely unrelated to those in existing scripts, each is 1B long and may contain parameters following them.
  7. If an unknwown opcode is encountered the annex verification succeeds immediately. (The signature, verified separately, could still be invalid which would make he transaction invalid.)
  8. Every opcode adds some data to the hash engine.
  9. After all opcodes are processed hashing is finalized and the resulting hash is compared to annex[0..32] - unequal means invalid transaction.

Note that 4) intentionally allows appending arbitrary data to the annex. This is intentional to allow future upgrades.

The initial version specifies three opcodes: OP_COMPACT_ADD which takes 2B argument treated as bit flags, OP_ADD_INPUT taking input index and flags, OP_ADD_OUTPUT taking output index and flags. Out-of-bounds indexes of OP_ADD_INPUT and OP_ADD_OUTPUT cause verification to fail. Each flag being set to true (bit 1) means to add specific chunk of transaction data to the hash engine. IOW, all zeroes means anyone can spend. An unknown bit being set succeeds the annex verification immediately.

The meaning of specific bits is yet to be determined but to give an idea what they would look like here are some examples:

  • For OP_ADD_OUTPUT bit 0 adds amount of the specific output to the hasher, bit 1 adds script_pubkey.
  • For OP_ADD_INPUT bit 0 adds the hash of previous transaction of the specific input to the hasher, bit 1 adds the index, bit 2 adds sequence number.
  • For OP_COMPACT_ADD bit 0 adds input count, bit 1 adds output count, bit 2 adds txhash of previous transaction of this input, bit 3 adds the index, bit 4 adds the sequence number, bit 5 adds amount of the output being at the same index, 6 adds script_pubkey of output at the same index, bit 7 adds remaining inputs, bit 8 adds remaining outputs, bit 9 adds transaction version, bit 10 adds the lock time...

In principle the initial version could have no opcodes, just to unblok CISA development but that wouldn't be very useful so perhaps there should be some minimal set of operations.

Noteworthy properties of the scheme

  • It is possible to aggregate and verify the signatures in parralel to the verification of annexes.
  • This adds at least 36 bytes for each smart contract using this feature.
  • The annex rules are completely isolted from signature verification which should avoid all unwanted interactions.
  • The design allows key owners to make signatures that cease to protect the coins as if the key was leaked.
  • The script version can be bumped just by adding a so-far-unused opcode at the beginning of the script.

Conclusion

By separating the selection of transaction data from signature verification it is possible to make CISA upgradeable with soft forks at the cost of more bytes for special contracts. The consumed space is hopefully justified by the benefit of upgradeability and parallel processing.

I ask all interested Bitcoin developers for consideration and feedback. Let's make CISA reality!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment