Bitcoin raw transactions part 2 : P2SH

Antoine Poinsot
Jan 31 · 4 min read

This post follows up the one which was about how to handcraft a raw Bitcoin transaction. I will this time describe the changes necessary to transform a classic Pay to Public Key Hash transaction to a Pay to Script Hash one.

Why Pay to Script Hash ?

P2SH was not an inbuilt transaction type in the early versions of bitcoin-core, it was introduced by Gavin Andresen, as a BIP : bip-0016. This paper describes perfectly why this new standard has been introduced :

The purpose of pay-to-script-hash is to move the responsibility for supplying the conditions to redeem a transaction from the sender of the funds to the redeemer.

What does Pay to Script Hash has introduced ?

  • Since P2SH, we can lock coins so that not only a single private key can unlock them, but also any condition the Script language permits. For example we can set a locking script saying : “provide a number so that the addition of 2 and this number equals to 3”. In Script, this condition is : OP_2 OP_ADD OP_3 OP_EQUAL.
  • Since P2SH, we have a new kind of address (they are still just an abstraction) which, once encoded in base58, starts with a 3 . This way you can send bitcoins to an address which can be unlocked under the conditions set by a script (from which the address is derived). We will describe how a P2SH address is formed below.
  • Since P2SH, the transaction size for the payer is fixed : the cost of fees (in sat/byte) is transferred to the redeemer of the funds who chose the condition.

How to form a P2SH output ?

In order to form such an output, firs we have to form the script which locks it. Let’s take as an example the following script :

OP_2DUP OP_EQUAL OP_NOT OP_VERIFY OP_SHA1 OP_SWAP OP_SHA1 OP_EQUAL

This script unlocks the coins if 2 different data are provided as input and so that their SHA1 hash is the same. In other words it is a bounty for finding a collision for the SHA1 algorithm, and it has already been claimed.

We take the corresponding opcodes of this script, as hex :

6e879169a77ca787

We then take the hash160 of the script as hex :

4266fc6f2c2861d7fe229b279a79803afca7ba34

The locking script the output is then, according to the bip-0016:

OP_HASH160 4266fc6f2c2861d7fe229b279a79803afca7ba34 OP_EQUAL

Thus the spender, who unlocks the script, has to provide a script which ripemd160(sha256()) hash is the same as the one provided in the locking script, and that evaluates to 1. The locking script size is constant, so that the cost in fees is transmitted from the payer to the redeemer of the funds.

It is possible to create non-spendable outputs, it means the script locking the coins just cannot evaluates to 1.

How to create a P2SH address ?

The format for P2SH addresses has been defined in bip13.

The encoding is the same as in classic P2PKH, and we’ll use the script hash instead of the public key hash. Using the same script as above, we would base58check the following data to get the P2SH address :

[version byte] [script hash] [checksum]0x01 0x4266fc6f2c2861d7fe229b279a79803afca7ba34 0xfdeb0664

Which results in :

37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP

How to spend a P2SH output / spend coins from a P2SH address ?

Let’s talk about the unlocking script. We know that this type of transaction moves the responsibility for supplying the condition […] to the redeemer of the funds. We will examine how to supply this condition in this paragraph.

Firstly, let’s look at the locking script which we append to our unlocking one : the first opcode is HASH160, which will hash the top item of the stack, and the rest of the locking script ( <hash of the chosen script> OP_EQUAL ) will check that the hash matches the one provided in the output. It will check that the script you provide is the same as the one in the locking script. This is how the condition is supplied.

Secondly, you’ll have to add some script in order to make the locking one evaluating to 1. Let’s take an example once again : I have an output which locking script is

a9145c9081ddd7c74d71e183b104abcc3f74be54c9c787 # EncodedOP_HASH160 5c9081ddd7c74d71e183b104abcc3f74be54c9c7 OP_EQUAL #Deco

I know that the hash corresponds to OP_2 OP_EQUAL . A script that makes it evaluates to 1 is simply OP_2 : the unlocking script will be :

<script to make it evaluate to 1> <locking script>
OP_2 OP_PUSH OP_2 OP_EQUAL

You noticed that we have to push the locking script. Here is a thread explaining why. Once encoded our unlocking script (also known as scriptsig) will be 52025287 . Here are our final scripts :

Decoded

OP_HASH160 5c9081ddd7c74d71e183b104abcc3f74be54c9c7 OP_EQUAL #lock
OP_2 OP_PUSH(2) OP_2 OP_EQUAL #unlock

Encoded

a9145c9081ddd7c74d71e183b104abcc3f74be54c9c787 # locking
52025287 # Unlocking

Links and references

Antoine Poinsot

Written by

Yet another Bitcoin promoter. twitter.com/darosior ~ github.com/darosior ~ crypto-lyon.fr ~ E13F C145 CD3F 4304