elements
Covenants in Elements Alpha
November 02, 2016
|

Bitcoin lets users choose rules to control how their funds can be spent and have them automatically enforced by the network. This programmatic facility enables users to set their own policies, from simple ones like multisignature to complex ones like trustless exchange. However, some policies do not currently have an obvious expression in the Bitcoin system. In this post we’ll talk about one such example, covenants, and describe how they can be implemented with a small extension to the Bitcoin script language that already exists in Elements.

A financial covenant is an agreement that restricts how funds (typically loans) may be used. The Bitcoin scripting language can be programmed to allow authorization schemes restricting who is allowed to create transactions spending particular funds. However, any party that is able to satisfy the authorization requirements is allowed to create any transaction with those funds. With covenants, one can create scripts that, not only enforce authorization schemes, but can also restrict the sorts of transactions that the funds can be spend with. For example, we can use the Möser-Eyal-Sirer vault to time lock transactions and detect malicious access to one’s funds.

Like Bitcoin, the Elements Alpha script language does not have direct access to the transaction data. Transaction data is only accessible indirectly through the OP_CHECKSIG and OP_CHECKSIGVERIFY operations. These operations take an elliptic curve public key and digital signature as inputs along with a signature hash type. They compute a double SHA-256 hash of the transaction data, modified in accordance with the specified signature hash type, and then perform a digital signature verification of the doubly hashed message data with the digital signature and public key. If the operation is successful, OP_CHECKSIG returns a value of 1 on the stack, otherwise it returns 0.

Elements Alpha’s new OP_CHECKSIGFROMSTACK and OP_CHECKSIGFROMSTACKVERIFY operations takes three inputs: an elliptic curve public key, a message, and a digital signature. The operations perform a single SHA-256 hash of the message and then perform a digital signature verification of the hashed message data with the digital signature and public key. If the operation is successful, OP_CHECKSIGFROMSTACK returns a value of 1 on the stack, otherwise it returns 0.

The trick to creating a covenant in Elements Alpha is using the fact that a successful OP_CHECKSIG operation means that the public key and digital signature together form a commitment to the transaction data. If the same public key and digital signature are used in a successful OP_CHECKSIGFROMSTACK operation then the message passed into OP_CHECKSIGFROMSTACK must be the same as the transaction data. Using OP_CHECKSIG and OP_CHECKSIGFROMSTACK together, we create a cryptographic guarantee that the message passed to OP_CHECKSIGFROMSTACK is the signed transaction data.

Covenant Construction

Consider the following script:

  1. OP_OVER OP_SHA256 <pubKey>
  2. 2 OP_PICK 1 OP_CAT OP_OVER
  3. OP_CHECKSIGVERIFY
  4. OP_CHECKSIGFROMSTACKVERIFY

Suppose two items are initially on the stack.

</code> {:.ui.segment} After step 1, we have hashed the `` once with SHA-256, and pushed a public key onto the stack. <sha256(sigTransactionData)> </code> {:.ui.segment} After step 2, we have copied the signature and public key onto the front of the stack. The signature has byte `0x01` appended to it. This is the code for `SIGHASH_ALL` hash type. It specifies that the signed transaction data contain all inputs and outputs. <signature;SIGHASH_ALL> <sha256(sigTransactionData)> </code> {:.ui.segment} The `OP_CHECKSIGVERIFY` of step 3 checks that a valid signature has been provided and proves that the transaction has been authorized with the private key. <sha256(sigTransactionData)> </code> {:.ui.segment} The `OP_CHECKSIGFROMSTACKVERIFY` of step 4 uses the same pubKey and signature. This operation performs a another SHA-256 and does a digital signature validation on the doubly hashed ``. Because we are using exactly the same pubKey and signature that we used for the previous `OP_CHECKSIGVERIFY` operation, this `OP_CHECKSIGFROMSTACKVERIFY` can only succeed if `` is identical to message that was checked during step 3's `OP_CHECKSIGVERIFY` operation. </code> {:.ui.segment} At this point in the script we are assured that `` is an exact copy of the signed transaction data. With full access to the transaction data we can add further script operations to enforce a covenant. We can restrict the number of outputs. We can restrict the values of the outputs. We can restrict the scripts of the outputs. This technique for covenants comes with some limitations. In Elements Alpha script, each stack item is limited to 520 bytes. This means that we can only create covenants for `` that is within this limit. However, we can create interesting covenants within this limit. ## Recursive Covenants In this section we will build a trivial recursive covenant. This covenant will restrict transactions to only ones that spend to a single output whose output script is the same as the input script. This covenant is a toy, but illustrates the basic recipe for building a recursive covenant. Later we will build more interesting covenants. Rather than putting the whole signed transaction data on the stack and parsing it, this script will assemble the transaction data from pieces. The script than can impose conditions on each piece to enforce the covenant. It is important the enforce that each piece of data is of a known fixed size, otherwise the script could be attacked by passing extra long or extra short pieces causing the script to think it is parsing one field of the transaction data when it is actually parsing another. Below is the scriptPubKey for our trivial covenant. 1. `<0x0100000001>` 1. `OP_SWAP` `OP_SIZE` `36` `OP_NUMEQUALVERIFY` `OP_CAT` 1. `<0x00>` `OP_CAT` 1. `OP_SWAP` `OP_SIZE` `32` `OP_NUMEQUALVERIFY` `OP_CAT` 1. `<0x00005f>` `OP_CAT` 1. `2` `OP_PICK` `OP_SIZE` `95` `OP_NUMEQUALVERIFY` `OP_CAT` 1. `<0xffffffff0100>` `OP_CAT` 1. `OP_SWAP` `OP_SIZE` `32` `OP_NUMEQUALVERIFY` `OP_CAT` 1. `<0x0000>` `OP_HASH256` `OP_CAT` 1. `<0x17a914>` `OP_CAT` 1. `OP_SWAP` `OP_HASH160` `OP_CAT` 1. `<0x870000000001000000>` `OP_CAT` 1. `OP_SHA256` 1. `1` `OP_DUP` `OP_CAT` `OP_DUP` `OP_CAT` `OP_DUP` `OP_CAT` `OP_DUP` `OP_CAT` `OP_DUP` `OP_CAT` `OP_DUP` `OP_CAT` 1. `OP_DUP` 1. `2` `OP_ROLL` `3` `OP_PICK` 1. `OP_CHECKSIGFROMSTACKVERIFY` 1. `1` `OP_CAT` `OP_SWAP` 1. `OP_CHECKSIG` The corresponding scriptSig to spend it is 1. `` 1. `