Ethereum Classic

Looking Into Bitcoin Scripts

On 31st October 2008, an unknown programmer named Satoshi Nakamoto released a whitepaper titled, “Bitcoin: A Peer-to-Peer Electronic Cash System“. Bitcoin was created in the wake of the 2008 financial recession. When the Lehman Brothers collapsed, people all over the world started losing faith in the central banking system. This is why, when Bitcoin came along, a lot of people started taking an interest.

What is so special about Bitcoin?

Bitcoin showed the world what a decentralized, peer-to-peer payment system can do. For the first time ever we had a currency that we had complete control over. You no longer needed to keep your money in a centralized bank, nor did you have to go through a bank to send and receive your money. You are your own bank. The money is kept in your own wallet and you can send and receive money by using public and private keys.

However, since Bitcoin only deals with transactions, it should be interesting to know what is happening behind the scenes. As you can imagine, behind every single transaction, there is some code that is working behind the scenes. This code is called the Bitcoin Scripting Language or just Bitcoin Script for short.

What is this Bitcoin Script?

Bitcoin script is a Forth-like, reverse-polish, stack-based, and a Turing incomplete language. Don’t be scared now, we are going to understand what each and every one of those term means.

What does “Forth” mean?

Bitcoin script is a lot like “Forth” which happens to be another stack-based programming language. Forth is known for its rapid development, minimalistic code, and high performance. Forth was mainly created for programming embedded and real-time applications. Nowadays, Forth is used creating applications on Windows, DOS, and variants of Unix that include macOS.

Using the Forth programming language you get:

  • Interactive development
  • Compact, efficient code
  • Modular software design
  • Incremental compilation
  • Great performance

According to experienced Forth programmers, using the language frees them to think “in terms of the solution instead of the tool. They say it encourages original, elegant solutions without penalty and without undue constraint. Some have said knowing Forth makes them better programmers in other languages.”

Reverse Polish

Reverse polish notation, sometimes referred to as postfix notation, is a way of writing mathematical expressions where each operand is preceded by the two operators it applies to. Let’s take an example:

2+3 will be written as 23+

Longer and more complex operations can also be represented via reverse polish:

  • 3+4*5 will be written as 345*+
  • (3+4)*5 will be written as 34+5*


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 a stack is LIFO or Last In First Out.

So, suppose we have this stack: apple, coconut, pineapple where apple was inserted first and pineapple last. Using the LIFO formation, the first element that leaves that stack will be the last one that went in. Similarly, the last element that leaves the stack will be the first one that went inside it.

In our stack above, the first element that leaves the stack is pineapple and the last element that leaves the stack is apple.

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

  • Push
  • Pop

Push: Pushing is the act of adding things into the stack. So if I want to add “banana” to our stack, we will “push” banana on to our stack, and the new stack becomes “apple, coconut, pineapple, banana”

Pop: The act of removing things from the stack is called popping. So, if we pop our new stack, using the LIFO formula, “pineapple” gets removed and the new stack becomes “apple, coconut, pineapple”.

Turing Incomplete

Turing Completeness means that given resources and memory, a program will be able to solve any problem. Solidity is an example of Turing Complete Language. A Turing Incomplete language, on the other hand, will have limited functionality as compared to Turing Incomplete languages. They are not capable of making jumps nor are they capable of loops.

However, the fact is that all languages don’t need to be Turing Incomplete. 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.

How Do Transactions in Bitcoin Work?

If you want to send some $5 to your friends, how is the transaction supposed to work? Well, you will meet your friend and, take out $5 from your wallet and give it to him, right? However, what happens when it comes to Bitcoin?

Bitcoin is a digital asset, which means that it isn’t something physical that you can just carry around in your leather wallet. Transactions in Bitcoin works in a different way:

  • You sent your intent of transacting with your friend to the miners. You sign off on the transactions with your digital signature
  • The miners first check the validity of the signature. If the signature doesn’t hold out, then the transaction falls through. If it does hold out then the transaction details are added to the blockchain
  • Once the transaction is added to the blockchain, your friend’s wallet is credit with the number of bitcoins that you sent them.

That’s the general overview, now let’s look deep into it. There are two sides to a transaction:

  • Transaction Input
  • Transaction Output

Transaction Input


In order to actually send bitcoin, Alice needs to retrieve the unspent bitcoins or the “change” that she has leftover from her previous transactions. We call these unspent bitcoins UTXO or unspent transaction output.

To understand how UTXO works, let’s just draw a parallel with real-world transactions.

Suppose you have a $100 note in your wallet. You go to the shop and buy groceries worth $30. After that, you get $70 worth of change back right?

Now, if you were to go to another shop, how do you make this transaction? You will be using the change that you got from your previous transaction right? That is exactly what unspent transactions or UTXO is.

Imagine that Alice has done 3 transactions prior to this one labeled TX(0), TX(1), and TX(2) respectively. The important thing to remember here is that transaction output counting starts from 0 and not 1. So the first UTXO is labelled UTXO(0).

If the change that she has left over from these three is enough to cover the bitcoins needed for her transaction with Bob.

So, her TX(Input) = TX(0) + TX(1) + TX(2).

Transaction Output

The output part of the transaction is pretty straightforward. Bob will get the number of Bitcoins that he is owed and Alice gets back the remaining Bitcoin as change. So the transaction looks like this:

TX(Input) = TX(Output) + Change + TX(Fees).

TX(Fees) is the fees that are taken by the miners to validate this transaction.

The “Change” goes back to Alice and she can use it as UTXO for her subsequent transactions.

There are some rules that these transactions should follow:

  • TX(Input) should always be greater than or equal to TX(Output) + TX Fees. If this condition isn’t met then the miners simply invalidate the transaction.
  • Alice sends the Bitcoin’s to Bob’s public address. Bob, however, can’t just obtain the Bitcoins straightaway. He must prove that he is indeed who says he is. The way he can do that is by unlocking the funds using his private key.
  • Alice also must prove who she is by validating her identity. Only after validation by the miners can her transactions go through. The way she does this is by signing off her transactions with her private key. Anyone decode her signature using her public key(which is publicly available). This proof is called “Signature data.”

Transactions in Bitcoin also happen to have names. How is this entire transaction going to be named?

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.

Closer Look at Inputs and Outputs

Let’s look at the code behind transaction inputs and outputs.

Transaction Output

Every transaction output consists of two parts:

  • The value of that output
  • The scriptPubKey/witness script/locking script: This is the cryptographic puzzle that needs to be unlocked in order to spend the money. We will see how these are unlocked in the next section.

Let’s look at the code in order to understand how it works.


“vout”: [


“value”: 0.05500000,

“scriptPubKey”: “OP_DUP OP_HASH160 ab68025513c3dbd25gb92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG”



“value”: 0.00450000,

“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.055 BTC while the other has a value of 0.0045 BTC. In order to unlock the value of 0.055, the locking script that one needs to unlock goes like this:

“scriptPubKey”: “OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG”

Transaction Input

Now, let’s look into how transaction inputs work.

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.2 BTC to Bob and her UTXO set looks like this:

  • UTXO 0 = 0.09 BTC
  • UTXO 1 = 0.2 BTC
  • UTXO 2 = 0.005 BTC

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

Now, let’s look at a random 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: Remember how we said that UTXO has “scriptPubKey” which is a locking script? This scriptSig is going to unlock that transaction.
  • sequence: Was included to help people update their transactions before they are confirmed and finalized in a block. This isn’t relevant anymore

Alright, so we have had a glimpse of how the script works, now let’s get into the nitty-gritty.

How Does Script Work?

Like we have said before, Script is stack-based and follows the reverse-polish notation. Let’s look at how reverse-polish can be represented in the stack form.

Let’s just do some simple addition in a stack-based reverse-polish system

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

Step 1: Let’s push 1 onto the stack.

Stack: 1

Step 2: Now we will push 2 on to the stack

Stack: 1 2

Step 3: Up next we have the “+” operator. The mathematical operator pops the numbers from the stack. Since “+” will need two elements, it will pop two elements from the stack. So, as we have said before, popping follows the LIFO standard.

So, in our stack, “2” will get popped first. Our new stack looks like this.

Stack: 1

Step 4: Now the “+” operator will pop the second element, so it will pop “1”. So right now, our stack is empty.


Step 5: The addition operation now happens, so 3+4 is now 7


Step 6: “7” gets pushed on to the stack,

Stack: 7

So, that’s how a simple addition operation gets done on the stack. How do we reprsent them in code form?

Like this:


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.

More Equations with Stack and Reverse Polish

Suppose we want to do 1+3=4. In Reverse Polish it will look like “23+5=”.

In script notation, it will look like this: OP_1 OP_3 OP_ADD OP_4 OP_EQUAL

Now, let’s start with the stack :

Step 1: 


Let’s push 1 onto the stack.

Stack: 1

Step 2: 


Now we will push 3 on to the stack

Stack: 1 3

Step 3: 


Up next we have the addition operator which will pop two elements, one at a time. So firstly, they are going to pop “3”

Stack: 1

Step 4: 


After that, they are going to be popping the second element, which in this case happens to be “1”. Right now the stack is empty.


Step 5: 


Now the addition operation happens, and 1 and 3 are added to give “4” and it gets pushed to the stack

Stack: 4

Step 6: 


“4” now gets pushed to the stack

Stack: 4 4

Step 7: 


Now Equal is going to pop the last 2 elements out one by one.


Step 8:


The two elements that have been popped are then equated with each other. If they are equal then “True” gets pushed onto the stack, if not then “False” gets pushed.

In this case, since they are equal, “True” gets pushed on to the stack.

Stack: True


There are two equal operations that will be used in Bitcoin script:


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. It is important that you keep this in mind for future examples.


Let’s kill two birds with one stone.

Let’s see how EQUALVERIFY will work while also introducing another important opcode, OP_DUP. OP_DUP is the duplication opcode and what it does is that it pops the last element, duplicates it, and then pushes the original and the duplicate back on the stack.

Let’s see how it is implemented via stack. The script that we want to implement is:


Step 1: 


Let’s push 3 onto the stack.

Stack: 3

Step 2: 


Now the OP_DUP will pop the last element from the stack. The stack will be empty now.


Step 3: 


The element is now duplicated and they are both pushed onto the stack.

Stack: 3 3

Step 4: 


Now EQUALVERIFY is going to pop the last two elements from the stack


Step 1: 


Now, since the two elements are equal, and since we have used “EQUALVERIFY” the result i.e. “True” will not be pushed onto the stack, the operations will simply continue.

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.

Transaction Locking and Unlocking

Transactions in Bitcoin are all about 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, how exactly do transactions work in Bitcoin? Suppose you want to send some Bitcoin to your friend Bob, you send them to his public address which is a hash of his public key along with some extra information. The public key is derived mathematically from your private key. You should never share your private key because whoever gets them has full control of your friends.

Whenever you sign off on transactions, you use your private keys to validate the fact that it is indeed you who is sending the transaction. Oh and btw there is another thing that you should take a look at.

This is what a public address looks like this: 1CmWotWnsCyczUqbrgqQg8TP9M6S2VUdRM

Its corresponding private key looks like this: 5JSVWbHUTWn16i15vGWC7ENPSvhzd6FBrpTREiU6uFw7mSreAEC

Did you notice how the private key is significantly longer than the public address? So, how is the public address derived from the private key? Well, let’s take an example:

  • First, you will generate your 256-bit private key. You can either do it manually or you can use a random key generator.
  • After that, your wallet will automatically generate your public address for you via an inbuilt algorithm. Let’s see how that happens.
  • The private key will be passed through a SHA-256 algorithm to get the first hash
  • The hash then goes through a RIPE MD 160 hash function. It generates a new hash and a copy of it will be kept aside, let’s call this H1
  • The hash is then again passed through SHA 256 to get another hash.
  • This hash is…well…passed through SHA 256 again to generate another hash. The first 7 bits of this hash is saved and let’s call it H2.
  • H1 and H2 are added up and the result is your public address.

As you can see, the process to generate the public address from the private key is so complicated, it is infeasible for this process to be reversed. In fact, it will take the world’s most powerful computer 40000000000000000000000000000000 years to complete this calculation!

How Transaction Gets Sent

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.

Like we have mentioned before, the way Bob is going to unlock his funds is via his digital signature which is cryptographically derived from his private key.

So, if we were to remember our script again:

  • 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: OP_HASH160 and OP_CHECKSIG 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:

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

The Unlocking/Verification Process via Script

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

Right now, the code looks like this:

Step 1:

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

<Bob’s signature> gets pushed onto the stack.

Stack: <Bob’s signature>

Step 2:

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

<Bob’s public key> gets pushed onto the stack.

Stack: <Bob’s signature><Bob’s public key>

Step 3:

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

The OP_DUP pops the last element, in this case <Bob’s public key>, out of the stack.

Stack: <Bob’s signature>

Step 4:

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

The OP_DUP duplicates <Bob’s public key> and pushes both the elements on the stack

Stack: <Bob’s signature><Bob’s public key><Bob’s public key>

Step 5:

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

OP_HASH160 is the hashing opcode. It pops the last element from the stack, which in this case is <Bob’s public key> and runs it through the SHA-256 hash algorithm, which gives a hash output which is 256 bytes long. After that, it runs through the RIPEMD-160 hash function which outputs another hash which is only 160 bytes long.

After going through both the hash functions, <Bob’s public key> becomes <Bob’s public address>

Stack: <Bob’s signature><Bob’s public key>

Step 6:

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

In this step, the <Bob’s public address> gets pushed on to the stack

Stack: <Bob’s signature><Bob’s public key><Bob’s public address>

Step 7:

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

Now <Bob’s public address> gets pushed on to the stack.

Stack: <Bob’s signature><Bob’s public key><Bob’s public address><Bob’s public address>

Step 8:

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

The OP_EQUALVERIFY pops two elements from the stack. So both the “<Bob’s public address>”s get popped from the stack.

Stack: <Bob’s signature><Bob’s public key>

Step 9:

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

EQUALVERIFY will now check if both the items are equal or not. Since it is, the operation keeps on continuing without pushing anything new on to the stack.

Stack: <Bob’s signature><Bob’s public key>

Step 10:

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

The CHECKSIG opcode pops the last two elements from the stack and checks to see their validity to know that they are valid signatures and public addresses.

And… the process if finished! 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.

Alright, so since we introduced you to the OP_CHECKSIG opcode, let’s look at how it works.


In order to know how CHECKSIG works, we will need to know what a digital signature is. The digital signature algorithm used by Bitcoin is ECDSA or the Elliptical Curve Digital Signature Algorithm.

Bitcoin, Ethereum and most of the cryptocurrencies use elliptical curve cryptography for encryption purposes. An elliptical curve is any curve that follows this 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 following this equation and more often than not, the following is how one of these curves, in general, will look like:

What are the properties of an elliptic curve?

  • The curve is symmetric across the x-axis i.e. the horizontal 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.

Mathematical properties of the curve.

#1 Addition property of the curve

Like we saw above, the second property of the curve is that any line that goes through 2 points on the curve will intersect it at a third point. Look at the graph below.

So, we have a line that is going through two points on the curve, V and A and it intersects the curve on a third point X. We will reflect the point X back into the curve and the curve will finally look something like this:

The reflection of X on the curve is going to be the result of the addition of V and A. So, the reflection of X is V+A. That, right there, is the additive property of the curve.

By the way, there is an interesting feature here.

If we add the a point with its reflection, i.e. if we added X to V+A, then the result will be infinity.

Can you tell why?

Any line that passes through X and (V+A) will intersect the club at infinity.

Multiplication property of the curve

Alright, so we have seen the additive property. But did you know that these curves have multiplication properties as well?

Think about it, when we multiply a number by two, what exactly are we doing? We are adding the number to itself, right? Similarly, when we multiply a number by 3, we are adding it to itself three times. Let’s use the same logic here.

Suppose we have a point V, what do we do to find 2V?

All that we have to do is to run a tangent through the point V. The point where it intersects the curve is reflected back onto the curve. The reflected point is 2V.

Now suppose we want to find 3V. We will join V and 2V and then reflect the point of intersection, like this:

Do you see how each multiplied point is cycling around the curve? That is how it gets its multiplicative property.

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.
  • The 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

We have seen how the multiplication property in the curve works. An interesting fact is that multiplication in the curve happens extremely fast. 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.

Instead of going through 99 steps we need to just go through 8 steps.

Property #3: Division on the curve is slow

Whilst multiplication is fast, the division is very slow. Suppose we have Q = nP and we want to find the value of n by dividing Q by P, there is no simple way of doing that. In fact, the only that you can go about it is by manually go through the numbers one by one to find a value which satisfies the equation.

This kind of a brute force solution is obviously extremely tedious and not recommended.

This is called the discrete logarithmic problem and this is what gives the curves its trapdoor function. So, while it is easy and fast to multiply, it is not really that practical and infeasible to divide

The elliptical curve Diffie-Hellman key exchange

So, until now we have seen the various properties of the curve and we have also seen that the curve has a trapdoor function. Now how do we determine whether it is usable for cryptography or not?

For that, we need to get back our Diffie-Hellman key exchange.

How will you and your friend Bob come up with a common secret without explicitly knowing the information that the other person possesses? How are you two going to do this by using elliptical curves?

  • The two of you will publicly agree on a point on the curve that you want to use. Let’s say that this point is P. This will be public knowledge and known to everyone.
  • In secret, you will choose another point “a” and Bob will choose another point “b”
  • You will then compute the value “aP” and send it over to Bob. Bob will then calculate the value “bP” and send it over to you
  • The aP and bP values will be public knowledge, however, no one will be able to break it down and get the secret values a and b, because of division in these curves in infeasible. That’s the trapdoor function after all.
  • You will then multiply a with the bP you have received. Bob will multiply b to the aP that he has received.
  • You will end up with abP while Bob ends up with baP. Since the points are Abelian in nature, abP = baP.

So as we can see. The curve satisfies the Diffie-Hellman key exchange.

Signature Verification Work On The Elliptical Curves?

Signature verification is a critical process for cryptocurrencies. So, let’s look at how this happens on elliptical curves.

Before we see how the process works let’s check out certain variables and their meaning that we will be using 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.

Alright, so now that we have all the basics set up, let’s see how it actually works.

Signing a message

Public key Q = dG. (it is impossible to get the private key from Q and G because, as we have already seen, division is infeasible in elliptical curves).

Let’s multiply G with a random number “k” and plot that point on the graph. The coordinates of the point is (x,y) where (x,y) = kG.

Next, we need to 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 because these are the coordinates of our signature.

When all this is set up, we send the point (r,s) for verification.

Verifying a message

The verifiers will use a simple equation:

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

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

Remember one thing, the verifiers don’t have the x coordinate given implicitly to them from the message sender. The only have the values r and n.

But, since we already know that r = x mod n, we can simply solve for x. If the value of x matches with the sender’s then we know that the signature has been verified positively.

What’s Happening Behind The Scenes

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.

Weakness in Elliptical curves?

Elliptical curves have proven time and again that they are the best form of cryptography out there but, this doesn’t mean that they are free from any vulnerabilities.

  • If we choose a wrong curve, which ultimately loops into itself, then there is a chance that some iteration of a point will go back to the original point. So, we could have a situation where 500P = P, where P is any point on the graph.
  • A weak curve can also be chosen, which hackers can easily break into.

Having said that, while EEC may have weaknesses but they are pretty manageable weaknesses.

RSA vs EEC. Why did Bitcoin and Ethereum Go With EEC?

The reason why EEC was chosen over RSA is that it offers the same level of security as RSA by consuming far fewer bits.

In fact, a 256-bit key in EEC offers the same level of security as an RSA 3072-bit key! Similarly, a for a 384-bit key in EEC the RSA will have to provide a 7680- bit key to provide the same level of security.

Also, consider this.

The NSA has declared that a 384-bit key in EEC is strong and secure enough to encrypt top-level secret documents.

NOTE: From here on out, we won’t be using the “OP_” command as frequently because it should be understood that “OP_” will always be prefixed to each opcode. Please keep this in mind. We didn’t use “OP_” to enhance readability, when you are executing the script please remember to use “OP_”.

Till now we have dealt with simplistic one-to-one transactions. However, real transactions are way more complicated. There are two things that we need to look into:

  • Multisignature transactions
  • Pay to script hash

Multisignature Transactions

In a multi-signature transaction, the only way that the bitcoin outputs can be unlocked is if multiple people verify the transaction. So, can you guess why multisig transactions are so useful?

Suppose there is a huge piece of land that is owned by 4 people. It will be extremely unfair if only one person was in charge of all the rights to the property, right? The only fair thing to do here is to have a condition where only a majority of the people can make important decisions related to the land, right?

Similarly, think of a huge multi-national company. Just one person will not be in charge of its funds, right? The money will be owned and controlled by a group of people (eg. the board of directors). This group’s majority will decide where the money flows.

Now, how do we replicate this in bitcoin script transactions? multisignature scripts of course!!

Multi-signature scripts set a condition where N public keys are recorded in the script and at least M of those must provide signatures to unlock the funds. This is also known as an M-of-N scheme, where N is the total number of keys and M is the least number of signatures required for validation. The transaction is also called M-of-N multisig.

The script format of a multisig output looks like this:

M <Public Key 1> <Public Key 2> … <Public Key N> N CHECKMULTISIG

Alright so let’s take an example of a company and see how it works. Suppose you opened up a company with 2 friends, let’s name them Alice and Bob.

Let’s say you put a condition that two out of you three need to verify any transaction for it to go through. For this, you will implement a 2-of-3 multisig.

How will the output look like?

2 <Public Key You> <Public Key Alice> <Public Key Bob> 3 CHECKMULTISIG

Alright, so this is the output. How will the company unlock the output and gain access to the funds? Remember that this is a 2-of-3 multisig meaning, 2 out of the 3 people involved must present their signatures.

So, the signature combination used can be any of the following:

  • <Signature You> <Signature Alice>
  • <Signature You> <Signature Bob>
  • <Signature Alice> <Signature Bob>

Suppose You and Alice are the ones verifying the transaction. The complete validation script will then read like this:

<Signature You> <Signature Bob> 2<Public Key You> <Public Key Alice> <Public Key Bob> 3 CHECKMULTISIG

IF the conditions above hold true and the signatures are correct, then the transaction will be TRUE and it will go through. However, if the signatures are incorrect, then the transaction will fail.

However, there is a little problem.

You see, the script that we gave above:

<Signature You> <Signature Bob> 2<Public Key You> <Public Key Alice> <Public Key Bob> 3 CHECKMULTISIG

…is incorrect.

Do you know why?

Well, turns out that there is a bug in the CHECKMULTISIG opcode.


Ideally speaking, a CHECKMULTISIG opcode should pop out M+N+2 elements out from the stack. Let’s look into our example script again and see how it gets executed in the stack:

<Signature You> <Signature Bob> 2<Public Key You> <Public Key Alice> <Public Key Bob> 3 CHECKMULTISIG

Before CHECKMULTISIG gets executed, the stack will look like this, basicaly the whole thing but in reverse:

Stack: 3 <Public Key Bob> <Public Key Alice> <Public Key You> 2 <Signature Bob> <Signature You>

CHECKMULTISIG, in essence, pops out all elements (M + N +2) in the stack. So, in script above:

  • M = 2
  • N = 3

The total number of popped elements should 2+3+2 = 7.

However, because of a glitch in the opcode, it pops out one more item than there are available in the stack. So, in this case, it will pop out 7+1 = 8 elements. This obviously ends up causing a stack error.

So, to avoid this error, we begin the script with a 0.

0 <Signature You> <Signature Bob> 2<Public Key You> <Public Key Alice> <Public Key Bob> 3 CHECKMULTISIG

Now, our stack will look like this:

Stack: 3 <Public Key Bob> <Public Key Alice> <Public Key You> 2 <Signature Bob> <Signature You> 0

By adding that one extra element “0” in the beginning, we make sure that we don’t face any errors.

This also means that instead of using this unlocking script:

<Signature You> <Signature Alice>

We end up using this:

0 <Signature You> <Signature Alice>

Pay to Script Hash

Mutilsignatures are amazing, however, they can get way too complicated if a lot of people are involved. Imagine a company which has 10 partners, and you need the approval of 6 people to get anything done. What will their script look like?

6 <Public Key 1> <Public Key 2> <Public Key 3> <Public Key 4> <Public Key 5> <Public Key 6> <Public Key 7> <Public Key 8> <Public Key 9> <Public Key 10> 10 CHECKMULTISIG

As you can see, this becomes very cumbersome and has a whole of disadvantages, the main one being the bloated transaction fees.

Firstly, the company will actually have to relay this information and script to their customers.

The customers then will need to use a special bitcoin wallet software with the ability to create a custom transaction script. The resulting transaction would be fives times larger than a normal transaction and would need more fees.

Obviously, that’s not an ideal scenario. Something was needed to make Bitcoin scripts less complicated. So, the community decided that instead of a complicated multisig script, people will simply include the hash of the entire locking script.

In order to unlock and redeem the transaction, the receiver will need to present the original script along with the signatures. Since the sender is sending money to a hash instead of a public address, this type of transaction is called Pay to Public Script Hash or P2SH.

Now let’s look at how transactions looked before and after P2SH.

Before P2SH

Locking Script: 6 <Public Key 1> <Public Key 2> <Public Key 3> <Public Key 4> <Public Key 5> <Public Key 6> <Public Key 7> <Public Key 8> <Public Key 9> <Public Key 10> 10 CHECKMULTISIG

Unlocking Script: <Sig 1> <Sig 2><Sig 3><Sig 4><Sig 5><Sig 6>

After P2SH

Redeem Script:6 <Public Key 1> <Public Key 2> <Public Key 3> <Public Key 4> <Public Key 5> <Public Key 6> <Public Key 7> <Public Key 8> <Public Key 9> <Public Key 10> 10 CHECKMULTISIG

Locking Script: HASH160 <Hash of Redeem Script> EQUAL

Unlocking Script: <Sig 1> <Sig 2><Sig 3><Sig 4><Sig 5><Sig 6> <Redeem Script>

As it can be seen, the responsibility for supplying the conditions to redeem a transaction transfers from the sender to the redeemer who presents the redeeming script.

So, what would a script if P2SH was not used? Sans P2SH the bitcoin script for a 2 of 5 multisign would look like this:

2 <Public Key 1> <Public Key 2> <Public Key 3> <Public Key 4> <Public Key 5> 5 CHECKMULTISIG

Which would translate into something like this:

2 04C16B8698A9ABF84250A7C3EA7EEDEF9897D1C8C6ADF47F06CF73370D74DCCA01CDCA79DCC5C395D7EEC6984D83F1F50C900A24DD47F569FD4193AF5DE762C58704A2192968D8655D6A935BEAF2CA23E3FB87A3495E7AF308EDF08DAC3C1FCBFC2C75B4B0F4D0B1B70CD2423657738C0C2B1D5CE65C97D78D0E34224858008E8B49047E63248B75DB7379BE9CDA8CE5751D16485F431E46117B9D0C1837C9D5737812F393DA7D4420D7E1A9162F0279CFC10F1E8E8F3020DECDBC3C0DD389D99779650421D65CBD7149B255382ED7F78E946580657EE6FDA162A187543A9D85BAAA93A4AB3A8F044DADA618D087227440645ABE8A35DA8C5B73997AD343BE5C2AFD94A5043752580AFA1ECED3C68D446BCAB69AC0BA7DF50D56231BE0AABF1FDEEC78A6A45E394BA29A1EDF518C022DD618DA774D207D137AAB59E0B000EB7ED238F4D800 5 CHECKMULTISIG

That block of hash is what 5 public keys combined looks like!

Imagine customers sending that bitcoin script to send their bitcoin UTXOs.

Now, if that same hexadecimal block was parsed through SHA 256 followed by RIPEMD160, it would look something like this:


Now, would you rather have the vomit of alphabets and numbers we showed you earlier or this neat little hash? If you are like us, then you would probably choose the later right?

The P2SH version of the locking script would now look like this:

HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e EQUAL

In order to unlock, the unlocking script would now look like:

<Sig 1> <Sig 2> 2 Public Key 1 Public Key 2 Public Key 3 Public Key 4 Public Key 5 5 MULTISIG>

The combining of these two bitcoin scripts takes place in two stages.

Firstly, the redeem script is matched up against the hash to see if it matches up:

<2 Public Key 1 Public Key 2 Public Key 3 Public Key 4 Public Key 5 5 MULTISIG> HASH160 <HASH OF REDEEM SCRIPT> EQUAL.

If this bitcoin script returns TRUE then the second part of the unlocking takes place via this piece of code which takes place automatically. This one is our traditional multisig unlock:

<Sig 1> <Sig 2> 2 Public Key 1 Public Key 2 Public Key 3 Public Key 4 Public Key 5 5 CHECKMULTISIG

P2SH addresses always start with a 3 instead of 1.

3KP3okFKoGs53JqgyGB27pqaum8tCz2BvW <- A P2sh address.


So, there you have it.

This should give you a good idea about what Bitcoin scripts are how they work. We know that this was all a whole lot of information to take in at once. Take your time and carefully understand the code. Once you get the grasp of it, it will be super simple to understand.

Leave A Reply

Your email address will not be published.