Share and get +16 +16

The aim of this guide to help you understand the logic behind Bitcoin Script. Since there will be too much to cover, the guide will be divided into two parts.

Bitcoin was created for one purpose alone…transactions. Bitcoin was able to show the world that a payment system can exist on a decentralized peer-to-peer system. However, what goes on behind the scenes of these transactions? Behind every little transaction, there is some code working in the background. This code is the Bitcoin Scripting Language or just Bitcoin Script for short.

The Best Bitcoin Script Guide

Introduction to Bitcoin Script

Script is a Forth-like, stack-based, reverse-polish, Turing Incomplete language. Yes, that sounds very complicated, but it really isn’t. Let’s go through each and every term from reverse.

Turing Incomplete

A Turing Incomplete language will have limited functionality and not be capable of making jumps and/or loops. Hence they can’t enter an endless loop. Being Turing Complete means that given the resources and memory, a Turing Complete program will be able to solve any problem. Solidity is an example of a Turing Complete language.

So why isn’t Bitcoin Script Turing Complete?

Because it doesn’t need to be. Bitcoin Script doesn’t need to be as complicated as an Ethereum smart contract. In fact, if a script was Turing Complete, it would have given malicious parties the freedom to create complicated transactions and eat up the hash-rate of the Bitcoin Network and slow down the entire system.

Reverse Polish

Reverse polish notation is a system where the operators follow the operands.

Meaning:

3+4 will appear as 34+.

So, for longer more complicated sums:

5*3+4 will appear as 534+*.

Stack Based

Stacks are one of the most popular data structures out there. According to Wikibooks, they can be logically thought of as linear structure represented by a real physical stack or pile, a structure where insertion and deletion of items take place at one end called top of the stack.

The basic idea of stack is LIFO or Last In First Out. Consider the following stack of books:

What was the first book that was put on this stack? Lone Wolf & Cub right? What was the last book? Gardens of the Moon.

If one were to take out a book from this stack, Lone Wolf & Cub won’t be the book you take out first, Gardens of the Moon will be the first you take out.

Hence, Last In First Out.

The Last book that went on this stack pile will be the first book taken out.

Now, there are two stack operations that you need to know about:

Push.

Pop.

Push: The act of adding things into the stack is called pushing.

Pop: The act of removing things from the stack is called popping. As has been mentioned before, the last item which got pushed into the stack gets popped out first.

Image Credit: Wikimedia

Forth-Like

This one is pretty straight-forward. Bitcoin Script happens to resemble the programming language “Forth” which also happens to be stack-based.

So, now we at least know what script is, let’s understand how Transactions work.

How do transactions in a Bitcoin work?

Before we continue, a huge shoutout to Professor Donald J Patterson and his Youtube channel “djp3” for the explanation.

Suppose Alice wants to send a certain number of bitcoins to Bob. How does the transaction system in bitcoin work? bitcoin transactions are very different from Fiat wallet transactions. If Alice was to give $2 to Bob, she would physically take 2 dollars from her wallet and give it to Bob. However, things don’t work like that in bitcoin. You don’t physically own any bitcoin, what you have is the proof that you have Bitcoins.

There are two more things that you need to know:

The miners validate your transactions by putting the data inside the mines that they have blocked. In return for giving this service, they charge a transaction fee.

When it comes to FIAT currency , you don’t really keep track of how and where you got that specific note from. Eg. Open your wallet right now and take out all the notes and coins in it. Can you tell where exactly did you get each and every specific note and coin from? Chances are that you don’t. However, in bitcoin , the history of each and every single bitcoin transaction is taken note of.

Ok, so now let’s do a deep dive into how a bitcoin transaction between Alice and Bob takes place. There are two sides to a transaction, the Input, and the Output. This entire Transaction will have a name that we will figure out in the end. For now, let’s look at the dynamics.

Transaction Input

In order to make this transaction happen, Alice needs to get bitcoins which she has received from various previous transactions. Remember, like we said before, in bitcoins, each and every coin is accounted for via a transaction history.

So, suppose Alice needs to pull bitcoins from the following transactions which we shall name TX(0), TX(1) and TX(2). These three transactions will be added together and that will give you the input transaction which we shall call TX(Input).

Diagrammatically, it will look like this:

So, that is it from the input side, let’s check out what the output side will look like.

Transaction Output

The output basically will have the number of bitcoins that Bob will possess, post-transaction and any remaining change that is left over, which is then sent back to Alice. This change then becomes her input value for all future transactions.

A pictorial representation of the output side looks like this:

Now, this is a very simple transaction that has just one output (apart from the CHANGE), there are transactions that are possible with multiple outputs.

This is what the basic layout of the transaction looks like. For this entire thing to go through, however, certain conditions must be met.

Conditions of a transaction

TX(Input) > TX(output). The input transaction has to be always greater than the output transaction. In any transaction, the deficit between the input and the output (output+change) is the transaction fees that miners collect. So:



Transaction fees = TX(Input) – (TX(output) + Change).

In the input side:



TX(0) + TX(1) + TX(2) = TX(Input).



If Alice doesn’t have the funds necessary to carry out the transactions then the miners will simply reject the transactions.

Bob will have to show that he can provide the proof needed to get the bitcoins. Alice will lock the transactions with Bob’ public address . He will need to produce his private key to unlock the transactions and gain access to his fees.

Alice also needs to verify that she has the required rights to send over the bitcoins in the first place. The way she does that is by signing off the transaction with her digital signature (aka her private key). Anyone can decode this by using her public key and verify that it was indeed Alice who sent over the data. This proof is called “Signature data”. Remember this because this will be very important later on.

So, what is going to be the name of this entire transaction?

The Input (including the signature data) and the output data is added together and hashed using the SHA 256 hashing algorithm. The output hash is the name that is given to this transaction.

So, now lets a look behind the scenes and see what the transaction actually looks like.

The bitcoin Script Transaction: Behind the Scenes

This is what the transaction looks like in the code form.

Suppose Alice wants to send 0.0015 BTC to Bob and in order to do so, she sends inputs which are worth 0.0015770 BTC. This is what the transaction detail looks like:

Image courtesy: djp3 youtube channel.

The first line you see:

Is the name of the Transaction aka the hash of the input and output value.

Vin_sz is the number of input data since Alice is sending the data using only one of her previous transactions, it is 1.

Vout_sz is 2 because the only outputs are Bob and the change.

This is the Input data:

See the input data? Alice is only using one input transaction (in the example that we gave above, this will be TX(0)), this is the reason why vin_sz was 1.

Below the input data is her signature data.

Underneath all this is the output data:

The first part of the data signifies that Bob is getting 0.0015 BTC.

The second part signifies that 0.00005120 BTC is what Alice is getting back as change.

Now, remember that out input data was 0.0015770 BTC? This is greater than (0.0015 + 0.00005120). The deficit of these two values is the transaction fee that the miners are collecting.

A Closer Look at Transaction Outputs

As we have seen above, every input in a transaction turns into outputs, some of these outputs are spent, while some are unspent and becomes change. This change is also known as UTXO or Unspent Transaction Output. UTXO goes on to become Inputs in future transactions.

Every transaction output consists of two parts:

The value of that output.

The cryptographic puzzle which either called a locking script, or a witness script or a scriptPubKey. The puzzle needs to be unlocked in order to spend the money. This puzzle is coded using the bitcoin Script language.

So, let’s examine the outputs of a transaction to identify the above-mentioned parts in it. Code taken from Andreas M. Antonopoulos. “Mastering bitcoin.”

“ vout ": [ { "value" : 0.01500000 , "scriptPubKey" : "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG" }, { "value" : 0.08450000 , "scriptPubKey" : "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG" , } ]

Alright, so we have two outputs in the code given above.

One output has a value of 0.015 BTC while the other has a value of 0.0845 BTC. In order to unlock the value of 0.015, the locking script that one needs to unlock goes like this:

“scriptPubKey”: “OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG”

An Even Closer Look at Transaction Inputs

Now let’s looks at the other side of the coin, the transaction inputs.

In order to do an Input, the user’s wallet goes through their UTXOs and selects the ones which have enough value for the transaction to go through.

Eg. if Alice wants to send 0.15 BTC to Bob and here UTXO set looks like this:

UTXO A = 0.09 BTC

UTXO B = 0.2 BTC

UTXO C = 0.005 BTC

Which UTXOs will be chosen for this transaction? That ‘s correct, A and B will be chosen, and whatever is left over will become the UTXO for Alice’s next transaction.

Now, let’s look at an input code.

“ vin ": [ { "txid" : "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18" , "vout" : 0 , "scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf" , "sequence" : 4294967295 } ]

Let’s see what each part of the input script includes:

txid: The transaction ID refers the transaction from which this UTXO was generated. This helps keep track of the transaction

vout: This refers to which output from that transaction is being used. Eg. if that transaction had two UTXOs the first one will be labeled 0(because as we have seen before, counting starts from 0 and not 1) and the second one will be labeled 1. In this case, we are using the first UTXO i.e.UTXO 0.

scriptSig: As we have mentioned before, each UTXO contains a locking script. The scriptSig includes the data necessary to unlock the data.

sequence: Was included to help people update their transactions before they are confirmed and finalized in a block, Not really that relevant to help understand the basics.

Serialization of Transactions

Now let’s bring of this together and see what we have. When a transaction is relayed over a network, they are serialized. As Andreas Antonopoulos says,

“Serialization is the process of converting the internal representation of a data structure into a format that can be transmitted one byte at a time, also known as a byte stream.”

In the previous two sections, we saw a simple one input and one output transaction. if we were to serialize it and store it in hexadecimal format, what would it look like?

0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73 4d2804fe65fa35779000000008b483045022100884d142d86652a3f47 ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039 ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813 01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84 16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1 7b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab6 8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000 1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac 00000000

Yup, this author didn’t accidentally bang his head on the keyboard here… that’s what it actually looks like.

However, don’t get scared. We will make sense of it soon enough. Somewhere in that hexadecimal stream, we have out input data and our output data. Let’s find both of them!

The Output Serialization

The serialization of the output part of the transaction contains the following parts:

Image Credit: Andreas Antonopoulos “Mastering Bitcoin”

Now, what data about the output do we actually know?

There are two output values.

One output value is worth 0.015 BTC or 1,500,000 satoshis

In hexadecimal 1,500,000 is 16 e3 60, which when coded in little-endian i.e. least significant byte first notation gives 60 e3 16.

The scriptPubKey length is 25 bytes, which is 19 in hexadecimal.

So, take note of these pieces of information, let’s search for our output data.

0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73 4d2804fe65fa35779000000008b483045022100884d142d86652a3f47 ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039 ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813 01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84 16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1 7b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab6 8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000 1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac 00000000

The Input Serialization

The input serialization contains the following components:

Now can you locate the input of her transaction?

0100000001186f9f998a5aa6f048e51dd8419a14d8a0f1a8a2836dd73 4d2804fe65fa35779000000008b483045022100884d142d86652a3f47 ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039 ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813 01410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade84 16ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc1 7b4a10fa336a8d752adfffffffff0260e31600000000001976a914ab6 8025513c3dbd2f7b92a94e0581f5d50f654e788acd0ef800000000000 1976a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac 00000000

Alright, so what have we seen so far?

The outputs of a transaction and the UTXOs.

The inputs of a transaction.

How the entire transaction is being serialized.

Now, we know that UTXOs can only be used if they are unlocked. We know that input values have scriptSig which helps unlock them. How do they interact with each other?

Before we get to that though, we should have an idea of how calculations and operations happen in a bitcoin script.

How Does the Script Work?

Before we continue with Script, it will be helpful to understand how a stack-based, reverse-polish system works.



Simple Addition in a Stack-based Reverse-polish System

As we have said before 3+4 in reverse-polish will look like 34+, let’s execute the addition operation using a stack.

That’s how a simple addition operation gets done on the stack. Now that this is done, how would this look like if it were a script?

OP_3 OP_4 OP_ADD

Just the appearance changes, the rest of the operation remains the same as shown above. The “OP_” prefix is a signature of the Script language.

If you want a primer on the different Opcodes that are used in a script then click here.

Simple Addition Using Bitcoin Script with a Check

Now suppose we want to do 2+3=5.

In Reverse Polish it will look like 23+5=.

In script notation it will look like this:

OP_2 OP_3 OP_ADD OP_5 OP_EQUAL

Now, what would have happened if we used the postfix VERIFY in EQUAL? Meaning, instead of OP_EQUAL we used OP_EQUALVERIFY?

The moment you add the VERIFY suffix, TRUE or FALSE doesn’t get pushed on the stack, instead, the script continues executing if TRUE or it stops executing if it is FALSE.

This is what happens when you append “VERIFY” to an opcode. Keep this in mind for future examples.

Alright, let’s take one last example.

Simple Duplication in the Script

We are taking this example just to introduce you to an extremely important opcode, DUP aka duplicate.

Let’s, we want to push a number into a stack, duplicate it, and see if the two numbers are same or not (which it obviously will be).

We are going to use this script:

OP_5 OP_DUP OP_EQUALVERIFY

Alright, now you have an idea of how calculations get processed in bitcoin Script, let’s continue with our transactions and see how they get executed.

The Game of Locking and Unlocking

Transactions in bitcoin are a constant game of locking and unlocking. The UTXOs are locked up by the scriptPubKey while the inputs of the transaction contain the scriptSig. The idea of scriptPubKey is to offer a cryptographic puzzle which can only be unlocked via the corresponding scriptSig.

So, what exactly happens and how is this game played?

Suppose, Alice wants to send Bob some bitcoin. Bob’s public address is common knowledge and she will send her Bitcoins to Bob’s public address along with a condition, Bob must prove that it is indeed him who is getting the bitcoin.

Now, let’s go back for a bit, and revisit some basic concepts.

Everyone in bitcoin has two keys:

Private Key.

Public Key.

The public key is cryptographically derived from the private key.

Now, in order to get money sent to them, everyone must have a public address. The public is run through two hashing algorithms, SHA-256 and RIPEMD-160. The reason why we do this is to make sure that you have an extra layer of protection, IF in the case that someone somehow figures out how to generate your private key using your public key (which is infeasible).

Note: The public key first goes through SHA-256 to give a 256-bit output hash, and then that hash is run through RIPEMD-160 which gives a 160-bit output hash. So, the final output is a 160-bit hash.

Alright, so Alice will send the money to Bob’s public address along with a condition that Bob must show a proof, that it is indeed him who have gotten the money.

The proof that Bob uses to unlock the funds is his Digital Signature, which cryptographically derived from his private key.

Think of the transactions that Alice sends Bob as a locked chest, and Bob’s signature as the passcode.

Now, getting back to our script.

Alice sends Bob an output which has the scriptPubKey, which includes Bob’s address.

Bob unlocks the input using his signature of scriptSig which includes his signature and his public key.

So, how do we represent this in code?

scriptPubKey = OP_DUP OP_HASH160 <Bob’s public address> OP_EQUALVERIFY OP_CHECKSIG.

Note: How OP_HASH160 and OP_CHECKSIG works will be clear to you soon.

scriptSig = <Bob’s signature> <Bob’s public key>

In order to unlock the output and use his funds Bob concatenates or kinda joins the scriptSig and the scriptPubKey like this:

Image Credit: CryptoCompare

Alright, now let’s see how the script works to give poor Bob access to his funds. The script right now looks like this:

<Bob’s signature> <Bob’s public key> OP_DUP OP_HASH160 <Bob’s public address> OP_EQUALVERIFY OP_CHECKSIG.

Script Implementation of the Unlocking/Verification Process

Ok, now let’s see how the script implementation of the entire verification/unlocking process works.

Right now, the code looks like this

The OP_CHECKSIG pops out <Bob’s public key> and <Bob’s signature> and checks to see their validity to know that they are valid signatures and public addresses.

When this entire process is done, Bob can unlock the transaction and gets access to his funds.

Congratulations! You just went through an entire bitcoin transaction!

What you see here is the most common type of bitcoin transaction: The P2PKH aka The pay to public key hash.

So, what is this mysterious CHECKSIG operator and how does it work? Well, for that we need to look at the cryptography behind bitcoin.

How does CHECKSIG work?

In order to know how CHECKSIG works, we will need to know what a digital signature is. A digital signature is a digital code (generated and authenticated by public key encryption) which is attached to an electronically transmitted document to verify its contents and the sender’s identity.

The digital signature algorithm used by bitcoin is ECDSA or the Elliptical Curve Digital Signature Algorithm.

Elliptical curve cryptography is what is used by bitcoin, ethereum etc. for their encryption purposes. So what is an elliptical curve? An elliptical curve is any curve that satisfies the following equation:

Y^2 = x^3 + ax + b

Where (x,y) is a point on the curve and a and b are constants.

There are infinite curves that you can make. The following is how one of these curves, in general, look like:

Image credit: CSBreakdown youtube channel

What are the properties of an elliptic curve?

The curve is symmetric across the x axis.

Any line that goes through 2 points on the curve will intersect the curve on a third point.

Any tangent on the curve will intersect the curve on one more point.

Performing maths on the curve.

Addition property of the curve

Suppose there are two points on the curve V and A. Let’s trace those on the curve and put a line through them. This will intersect the curve on a third point.

Image credit: CSBreakdown youtube channel

We will call this third point X, and we will reflect it on the curve like this:

Image credit: CSBreakdown youtube channel

The reflection of X is a point which will incidentally be (V+A). This is the additive property of the elliptical curve.

Interesting note. If we add two reflections with each other aka if we were to add X and V+A in the graph above, we will get infinity. The reason for that is that the line through X and (V+A) will intersect the curve at infinity.

Multiplication property of the curve

Now, what if we want to add a number to itself? Like suppose we have a point V, what do we do to find 2V? We will run a tangent through V and intersect it at a point in the graph and then find the reflection of the point on the curve. That reflection will be 2V.

Image credit: CSBreakdown youtube channel

This is also the multiplicative property of the graph because we are finding points which are basically the multiplication of an integer with the point itself. Now suppose we want to find 3V. We will join V and 2V and then reflect the point of intersection, like this:

Image credit: CSBreakdown youtube channel

You see how the points cycle across the graph? This is what gives it its security.

Mathematical properties of an elliptical curve

Property #1: The points on the curve form an Abelian group

The properties of the Abelian group are as follows:

They have an identity.

They have inverses aka reflections.

The points are associative meaning for three points A, B and C on the curve: (A+B) + C = A + (B+C).

The points are closed on the curve.

The points are commutative meaning for two points A and B. A+B = B+A.

Property #2: Multiplication on the curve is fast

All multiplication done on the curve can be done very fast. Now suppose we have a point P and we want to find 100P. Instead of adding the number to itself 100 times we can do the following:

Add the point P to itself to get 2P.

Add 2P and P to get 3P.

Add 3P to itself to get 6P.

Add 6P to itself to get 12P.

Add 12P to itself to get 24P.

Add 24P and P to get 25P.

Add 25P to itself to get 50P.

Add 50P to itself to get 100P.

So, instead of going through 99 steps you cut short the entire thing to just 8 steps.

Property #3: Division on the curve is slow

Whilst multiplication is fast, division is very slow. Suppose we have Q = nP and we want to find the value of n by dividing Q by P. We can’t really do that. We will have to manually go through the numbers one by one to find a value which satisfies the equation. This makes it very slow. This is called the discrete logarithmic problem and this is what gives the curves its trapdoor function i.e. it is easy to multiply n and P to get Q but given Q and P, it is infeasible to get n.

So how does signature verification work on the elliptical curves?

(Note: This is what specifically happens in bitcoin)

Before we see how the process works let’s check out certain variables and their meaning that we will be using in the following equations.

Private key = d.

Message = z.

Public key = Q.

G will be a constant point on the graph which will be provided by bitcoin.

“k” is a random number which will be generated automatically for every unique signature.

“n” is another constant that will be provided by bitcoin.

Ok, so now let’s see how the maths behind the verification work’s.

Signing a message

Public key Q = dG. (it is impossible to get the private key from Q and G because of division in infeasible).

Now we will multiply the G with the random number “k” and plot that point on the graph. The coordinates of that point are (x,y). i.e. (x,y) = kG

Next, we determine two values r and s such that:

r = x mod n.

s = (z + rd) k^-1 mod n

The reason why we generate r and s is that these are the coordinates of our signature.

So, we send the point (r,s) for verification.

Verifying a message

The verifiers will conduct a simple equation:

z*s^-1*G + r*s^-1*Q

The value of this equation will give us the point (x,y).

Now, the verifiers can simply compare the x coordinates. They don’t have the x coordinate given directly to them by the sender BUT they have the values of r and n.

And as we already know that r = x mod n, and then they can simply solve for x.

If the values of x match out, then this means that the signature is verified!



Bonus: A deeper look into the maths

Let’s check out the equation that the verifiers will have to do once again:

Step 1: z*s^-1*G + r*s^-1*Q

We know that Q = d*G, let’s simply substitute the value.

Step 2: z*s^-1*g + r*s^-1*d*G

We can take (z + r*d) common

Step 3: (z + r*d)*s^-1*G

Now remember, we have already established that s = (z+r*d)*k^-1 mod n ,let’s substitute the values here:

Step 4: (z+r*d)*(z+r*d)^-1*k*G

The (z+r*d)*(z+r*d)^-1 cancel each other out and we are left with:

Step 5: k*G which is the co-ordinate (x,y) that the sender originally sent.

What could go wrong in Elliptical curves?

While it goes without saying that elliptical curves are the best mode of cryptography out there, the fact remains that it still has few vulnerabilities:

What if a wrong curve was chosen? If the curve has a loop in it then there is a possibility that 1001P = P for any point P on the curve.

A weak curve may be chosen which can be broken into.

It has its weaknesses but they are pretty manageable weaknesses.

END OF PART 1

This is where we are going to end the part 1 of our Bitcoin Script Guide. In part 2 we are going to cover:

Multisignature Transactions.

Pay to Script Hash.

Flow Control.

Timelocks.

Stay tuned for the next part!