Consider the following question. Is it possible to use the Bitcoin blockchain for smart contracts? By this, I am not asking how far we can push the rather limited functionality of the native Bitcoin Script. Rather, can we write code for something like the Ethereum Virtual Machine (EVM), which is a Turing complete computation engine used by the Ethereum blockchain, and run on Bitcoin? This would enable a great variety of different uses for Bitcoin, such as ERC20 tokens, decentralized exchanges (DEX), NFTs, zk-STARKS, and any of the many different types of contract used by Ethereum.
While your first answer to the question above is probably “no, this is not possible”, there is one way in which it can be done with, albeit, a rather large caveat. Bitcoin transaction outputs incorporate a script, which is a simple stack-based programming language used to restrict how the coins can be spent. Output scripts starting with the OP_RETURN opcode cannot be spent in any way. More than this, they are provably unspendable, so are ignored by Bitcoin nodes which do not even record such outputs in the UTXO set. The output quantity would likely to be set to zero, so as to avoid irretrievably destroying any bitcoin associated with the output. This means that we can include any arbitrary data following the OP_RETURN to be recorded on the blockchain, which is simply ignored by all validating nodes. This is one of the uses of Bitcoin, as an immutable and decentralized store of data.
So, all we have to do, is to include smart contract code in OP_RETURN outputs using whatever language, such as EVM, that we want. Ok, this does not form part of the protocol, so is ignored by Bitcoin nodes. Blockchain explorers would show the code as raw data, but would not interpret the contract language. This is a rather large caveat, and you may well reply that it is not really ‘running’ on Bitcoin and, really, all that we are doing is using the blockchain as data storage. However, it is interesting to consider and, even if due to reasons to be discussed below, it is not very efficient, these methods are implemented by the Omni Layer and also lead on to ideas such as Proof of Transfer. Continue reading “A Smart Contract Platform on Bitcoin?”→
The highly anticipated Bitcoin upgrade Taproot is locked in and set to be activated in November 2021. This will have various advantages, such as supporting Schnorr signatures and incorporating multiple possible unlocking scripts in an efficient fashion. The aim is to increase scalability, privacy and security, especially with more complex ‘smart’ transactions. These updates are all about how bitcoin utxos (unspent transaction outputs) can be spent, by introducing new ways of parsing the scripts. I previously posted about Bitcoin Script, describing both the legacy and SegWit methods. The current post extends the description to include Taproot.
The first thing to note, is that Taproot is a kind of SegWit implementation. This means that the scriptPubKey in the transaction output takes a standard form, and the witness field of the corresponding transaction input is used to validate the spend. As with other SegWit methods, the scriptSig of the transaction input is not used, so is left empty. The standard Taproot spend method is then as follows.
P2TR — Pay to Taproot
The Bitcoin core script recognizes a scriptPubKey of this special form, consisting only of the version number OP_1 followed by a 256 bit (32 byte) public key, and interprets as a Taproot spend. Then, for a witness field consisting of a single command, this is interpreted as the standard Taproot spend method with the witness field containing just the signature. To be valid, the signature needs to be a valid Schnorr signature using the provided public key and using the spending transaction as the message.
Note that this is very similar to the standard SegWit P2PKH method, with three main differences.
The scriptPubKey contains the public key itself, rather than a hash of it.
Schnorr signatures are used, instead of the legacy ECDSA signatures.
The scriptPubKey has version number 1 instead of 0.
I note that Taproot is a soft fork, since any Bitcoin node which does not include the Taproot upgrade will see the P2TR scriptPubKey as being an ‘anyone can spend’ address. As it would be interpreted as putting the public key on the top of the stack, such spends will still be seen as valid. This avoids a fork of the blockchain where non-upgraded nodes would potentially disagree with upgraded nodes on which is the valid chain. However, non-upgraded nodes would not be completely validating Taproot spends (potentially accepting invalid spends from Taproot addresses), reducing their effectiveness in securing the integrity of the blockchain.
Already, the simple spend method described above has some advantages, due to the use of the Schnorr signature method which can incorporate key aggregation to allow multisig to be used, as well as allowing more efficient batch validation of a collection of transactions in one go. However, the power of Taproot is in it incorporating alternative spend scripts, described below. Continue reading “Taproot”→
Cryptocurrencies such as Bitcoin make use of public key cryptography, in order to restrict the ability to spend a coin to the owner. Recall the idea from the earlier post on this subject: A prospective Bitcoin holder — Alice — has to first select a key pair. This consists of a private key, which must be kept secret, and a public key. If she purchases some bitcoin from another party — Bob — he needs to create a transaction on the blockchain paying this to an address corresponding to the public key. When Alice is ready to spend her coins, she creates a new transaction with the input, and signs it using her private key. Using the public key, anyone can verify that the digital signature is valid but, since only Alice can create a valid signature, only she is able to spend her coins.
For added flexibility, Bitcoin does not hard-code this procedure and, instead, makes use of a simple stack-based programming language called Script. A program, or script, in this language consists of a sequence of commands, usually written from left to right and which are executed in order. Each command in this language takes one of two forms. They can be of the form <data>, which simply adds the hardcoded data to the top of the stack. Such data is always a byte vector, which can also be used to represent a variable length integer or a Boolean true/false flag. Or, it is one of a finite set of defined opcodes, written with the prefix OP_. An example program performing digital signature verification can be written with just three commands.
<sig> <pubKey> OP_CHECKSIG
The first two commands push the digital signature ‘sig’ and the public key ‘pubKey’ onto the stack. The final OP_CHECKSIG performs signature verification, using the signature and key from the stack. The result is that it removes these from the stack and replaces them with True if the signature is valid, and False if it is not. So, the result of this program is that we have True or False on the stack depending on whether the signature is valid or not.
Note, I did skip a rather important part of digital signatures. The whole idea is that Alice is signing a message, so the verification procedure clearly requires this message as an input. However, the OP_CHECKSIG opcode only takes two arguments, the signature and the public key. This is simply because it implicitly uses the transaction that is spending the coins as the message.
I will not go over the full specification and possibilities of Script here but, instead, outline some of the ways in which it is used. For more details, see the Bitcoin Wiki.
I start by describing the original (or legacy) approach, before explaining the more recent segregated witness method. The idea is that a transaction output contains some script which plays the part of the public key restricting how the coin is spent, and is called a locking script, or the ‘scriptPubKey’. The corresponding transaction input spending these coins contains a redeem script corresponding to the digital signature, called the ‘scriptSig’. This is as in figure 1 below, showing two transactions and their input and output fields.
When validating the transaction, we execute them in turn, first the scriptSig from the transaction input and then the scriptPubKey from the corresponding transaction output. If the script finishes execution with the item at the top of the stack equal to True, then the transaction input is valid, otherwise it is rejected as invalid. Also, Script does not contain any loop constructs, and is always executed from left to right. This means that it is not Turing complete, but is a very important part of the design. As each command can only be executed at most once, it is not possible to have scripts that take a long time to run, and possibly never terminate, which would cause serious problems for validation.
We can take the final two commands of the simple script above (i.e., everything other than the signature) as the scriptPubKey, so that Bob includes this in his transaction output. To spend this coin, Alice creates a transaction with the digital signature <sig> as the scriptSig. Together, they create the three line script above, which validates only if Alice creates a valid signature. Alice could use a more complicated scriptSig if she likes but, in order for it to validate, it needs to leave a correct signature on the stack, and nothing else. So, scriptPubKey is a function determining if the transaction input is valid, and scriptSig simply pushes the required arguments on the stack.
This very simple type of locking script described above is known as P2PK, or pay to public key, but is considered obsolete.