Photo by Florian Olivo on Unsplash

Create Raw Multi-Sig P2SH Bitcoin Transaction in Golang

Bitcoin Script Language

Mahdi Darabi
6 min readDec 4, 2020

--

Bitcoin scripting language called Script is a stack-based (stack: first in, last out) execution language. It is designed to simplifying the security model of Bitcoin, so the Script has not any loop or jump op-code, and the language is not turing-complete. But this limited language provides a lot of capabilities to Bitcoin to write programs. You can find detailed information about Bitcoin script language in this link .

Pay to Script Hash (P2SH)

Pay to script hash (P2SH) transactions were standardized in BIP16. That update allows transactions to be sent to a redeem hash (addresses starting with 3 in main-net and 2 in test-net) rather than a public key hash (addresses starting with 1 in main-net and m in test-net). The sender doesn’t know anything about the redeem and only knows the redeem hash, and the redeem can be anything from a multi-sig checking or a password verification or anything else.

To spend Bitcoins in a P2SH UTXO, the recipient must provide a redeem-script that matches with the redeem hash in the UTXO and also a signature-script (known as sig-script) to spend Bitcoins.

In this tutorial, I will explain how to build a multi-sig address in the format of P2SH and then spend it with Go language.

Multi-Sig Redeem Script

m = the minimum number of signatures that are required to spend the UTXO (OP_2 = 2)

n = the total number of public keys, used in multi-sig script (OP_3 =3)

m and n can be up to 16

redeem script = <OP_2> <pubkey A> <pubkey B> <pubkey C> <OP_3> OP_CHECKMULTISIG
multi-sig redeem script in go

This is the return value of the above function: (public keys are bold)

2 0265e6f7fb614a369c9230912a3bb09c33c5c5be2e1bcfc2293ecaed46708e0b5c 03f546edf7b434b50aa0115c1c82a0f9a96505d9eff55d2fe3b848c4b51c06b643 02908375f301c7ea583f7e113939eab1164abda4ac27898b1cf78abf1c82f02da9 3 OP_CHECKMULTISIG

signature script = <OP_0> <sig A> <sig C>

(in the final code I’ll describe step by step how to construct this signature script)

Script Execution

The signature script along with redeem script will result a true in the stack.

signature script + redeem script = <OP_0> <sig A> <sig C> <OP_2> <pubkey A> <pubkey B> <pubkey C> <OP_3> OP_CHECKMULTISIG
  • From left to right, each op-code or data added at the top of the stack, and at last OP_CHECKMULTISIG is added
  • OP_CHECKMULTISIG gets the total number of public keys to check from the top of the stack (in this case OP_3)
  • and then gets the specified number of public keys (in this case 3, OP_3 = 3) from the top of the stack
  • and then gets the number of signatures that must be provided from the top of the stack (in this case OP_2 = 2)
  • at last check the stack for needed signatures, if the signatures would be correct, then leave a true on the stack and you can spend your Bitcoin

(OP_0 is added because of a known bug in Bitcoin script language that is now is a part of consensus, you can find full description here )

This is how Bitcoin script language works. Now we can dive into P2SH.

Multi-Sig P2SH

anyone who send to a P2SH address only need the redeem-hash (extracted from the address)

redeem-hash = Hash160(redeem script)

If somebody wants to build a P2SH address firstly have to generate the redeem script (that in our case generated Multi-Sig Redeem Script section), and hash it with hash160. so the redeem-hash is 20-byte length.

(hash160 is a two-step hash algorithm, that first hashing the input with Sha256 and hashing again its result with RIPEMD160, the final result would be the result of RIPEMD160 hash function)

After that build a P2SH address with the redeem-hash (starting with 3 in main-net and 2 in test-net)

multi-sig P2SH address generator

The return value of the function would be:

2NFhEhTAiXJ8z8yEYnXe6SJX5E8bRgB5ZgY

(starting with 2 because generated to use in test-net)

Now anyone can send bitcoin to this address. When a sender wants to send some amount of Bitcoin to this address, its wallet extracts the redeem-hash from the address and build a locking script to put in the output of the transaction.

locking script = OP_HASH160 <redeem-hash> OP_EQUAL

You can also use this link to get some test Bitcoin.

after getting some Bitcoin (test or real), you can check a block-explorer, for example api.blockchair.com to check the locking script, it’s also known as script hex or pubKey script.

locking script in block-explorer
dis assemble hex script into human readable script language

The return value of the above function, which dis assemble the locking script into human readable Bitcoin script language is:

OP_HASH160 f63e2cbcc678236f683d267e7bb298ffdcd57b04 OP_EQUAL

Spend Multi-Sig P2SH

When the recipient wants to spend this UTXO should provide an unlocking script, that is the signature script concatenated with the redeem script.

unlocking script = <OP_0> <sig A> <sig C> <redeem script>

The miners add this unlocking script to the locking script that is on the blockchain and then run the program.

script program = unlocking script + locking script

script program = <OP_0> <sig A> <sig C> <redeem script> OP_HASH160 <redeem-hash> OP_EQUAL
  • <OP_0>, <sig A>, <sig C>, and <redeem script> will be added to the stack one by one
  • Then OP_HASH160 added and calculate the hash of the top element of the stack, which is <redeem script> and leaves the result on the top of it
  • Then <redeem-hash> added on the top of the stack
  • at last OP_EQUAL will be added
  • OP_EQUAL checks two top elements of the stack, (which in this case are HASH160(redeem script) , and <redeem-hash>)
  • if they would equal leaves a true and continues the program and if they would not equal leaves a false at the top of the stack and breaks the program
  • So if the recipient provides the same redeem script, that is used for building the redeem-hash and the address, then we reach to the same state as Script Execution section, with the same op-codes and data on the stack

this is the code that sign a multi-sig transaction in go, if you are not familiar with bitcoin transaction and its structure, you can see my previous post .

this is the return value of the above function:

0100000001fe75a438b72fdc302b80cc216d66d5e3bbb0359bce3bb4cecf743f5fda1f4eb101000000fdfd000048304502210096b617a5b2bd676ee8d3f8d8d91bf60c599e16382d1e12a61a1f9562c35b2cb102204379706a55c07bb45d20336159f80ebe9786938e34b9309e49ed422e6d2a44470147304402201550a8bb0c28107098289fe6fe64488bdee46800d28bfbb0b0a1e1b2d64b9fb4022004684015095b999185b3da1a23d239452ad73b199a032f71978760f8ae42313f014c6952210265e6f7fb614a369c9230912a3bb09c33c5c5be2e1bcfc2293ecaed46708e0b5c2103f546edf7b434b50aa0115c1c82a0f9a96505d9eff55d2fe3b848c4b51c06b6432102908375f301c7ea583f7e113939eab1164abda4ac27898b1cf78abf1c82f02da953aeffffffff01f8a70000000000001976a914bd63bf79e39f4cd52361c092c3fba9264662285688ac00000000

this is a raw bitcoin transaction that can be push in the test network, you push your one from blockstream.info or anywhere else.

the txid of the above raw transaction is:

c7d1582d4cf85fbd10732002c5bb06068d4b86cfd5cca151ef88104c6702435a

you can search it in any block explorer for Bitcoin test-net.

bitcoin test-net block-explorer

You can find about P2PKH transaction, transaction structure, and fee in my previos post .

Thanks for your attention

Also, Read

Get Best Software Deals Directly In Your Inbox

--

--