With the recent surge of mainstream media coverage of Bitcoin and cryptocurrencies in general, a lot of people are now purchasing their first Bitcoin. With the dedicated support from many open source developers, Bitcoin’s user interfaces have gotten better and better at shielding the user from the complexities underlying the architecture. This allows most users to transact and to experiment with Bitcoin without having to worry about the technical aspects. However, with the scripting system, Bitcoin transactions allow the user to perform complex tasks that will execute on the blockchain, on top of the payment system.

To start with, Bitcoin ledgers differ from the conventional financial system in that it doesn’t track the number of coins per wallet but rather the history of transactions. Each transaction specifies a list of input transactions and a list of output addresses, each with a coin value associated with them. However, because the identity of the sender needs to be verified, in addition to whenever he is allowed to spend the transactions that he included, a simple ledge entry of the style “Alice sends 5 BTC to Bob” will not suffice. This is where the scripting system comes in.

The Bitcoin scripting system is a simple stacked-based language with only 256 operations, one byte for each operation. It has the common operators in any programming language such as arithmetic operators, control-flow operators, logic operators, etc. However, since Bitcoin transaction scripts have to be processed by the nodes on the network, it is intentionally not Turing-complete to avoid infinite loops and such. More information on the list of operators can be found on the Bitcoin Wiki.

A sample transaction with 2 inputs and 2 outputs. Note that the scripts are in hexadecimal format

A part from the metadata, a transaction has two major components, the inputs, and the outputs. In the sample transaction here, we can see that a script parameter is associated with each input and output. For each output, a script called scriptPubKey is specified along with the coin value intended for the output. For each input, the transaction must specify the hash the transaction as well as the index of the output. Remember that a transaction can have multiple outputs, so it is important to specify which output of the given transaction is being processed. More importantly, with each input, the sender must specify a script called scriptSig. This script proves that the sender has the authorization to spend the transaction. In most cases, this value is a cryptographic signature of the public key of the sender. It is important to note that Bitcoin transactions are not sent to a wallet or a person directly. Instead, it is broadcast to the entire network and whoever can provide the correct scriptSig to the transaction can use it as input in their own transaction. To verify that the sender is allowed to send the input transactions, the scriptSig is prepended to the scriptPubKey of the previous transaction the input is referring to, and the combined script is executed. If the combined script terminates without error, the transaction is considered valid.

The best way the understand Bitcoin scripting is through an example. Let’s look at a simple transaction where Alice wants to spend a transaction that Bob has previously sent her. This type of transaction is the most common and is called pay-to-pubkey-hash, or P2PKH. The scriptPubKey of Bob’s transaction would look like this:

OP_DUP OP_HASH160 <AlicePublicKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Here, <AlicePublicKeyHash> is simply a hash of Alice’s public key. To redeem this output, Alice has to provide the following scripSig:

<AliceSig> <AlicePubKey>

The scriptSig only contains two elements, Alice’s public key and a signature that she generated using her private key, proving that she is the creator of this script. The combined script will look like this:

<AliceSig> <AlicePubKey> OP_DUP OP_HASH160 <AlicePublicKeyHash> OP_EQUALVERIFY OP_CHECKSIG

First, both Alice’s signature and her public key are pushed onto the stack. Then, a duplicate operation is performed on the top-most item of the stack, which is the public key. The key is then hashed through OP_HASH160 , a built-in cryptographic operator. The public key hash specified by Bob is then pushed onto the stack and is compared with the generated public key hash. Assuming that the equality holds true, Alice’s signature and her public key are left on the stack, OP_CHECKSIG will then verify that the signature is indeed valid and ends the transaction without error. If the signature is not generated by Alice, the operation would fail and the transaction is marked as invalid.

Bitcoin script gives the sender much more flexibility in defining how the recipients receive the transactions. In fact, one can create interesting puzzle transactions that anyone can spend, but only when certain criteria have been met. For example, in 2013, Peter Todd published a few hash collision bounty on bitcointalk forum. The collision bounty for SHA1 algorithm looks like this:

OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL

The first half takes a copy of both submitted strings and makes sure that they are not equal. The second half computes the hash for each one and checks if they are the same. To include this output in your own transaction, you would have to provide 2 different strings that when hashed with the SHA1 algorithm, gives the same result. Other interesting scripts include pay-to-multisig where more than one person’s signature is required to spend the coin, time-locked transactions where the coins are not spendable until a predetermined time, and many more.