Bitcoin
Blockchain
仮想通貨
暗号通貨

はじめに

この記事は、暗号通貨 Advent Calendar 20日目の記事です。Bitcoinのトランザクションには欠かせない、ロジックの部分を担っているScriptについて解説します。プログラミングや初歩的な数学の知識、ビットコインの概要の理解を前提としています。この記事を読んで、最も典型的なP2PKHのScriptを理解できるようになることが目標です。私は情報学の専門ではないので、間違いがあったらコメントや編集リクエストで指摘していただけるとありがたいです。

Transactionの構造を理解している前提の記事なので、Mastering Bitcoinのトランザクションの章やこの記事を事前に読むことをおすすめします。

Scriptとは

Scriptとは、Bitcoinのトランザクション内に書かれるプログラミング言語の一種です(チューリング完全ではないのでプログラミング言語といってよいのかは微妙)。左から右に向かって処理され、LIFO (Last In First Out)と呼ばれるデータ構造を持ちます。例えば、普通のプログラミング言語だと、

5 + 2

というように書かれますが、実際の手順は

  1. メモリに5を用意する
  2. メモリに2を用意する
  3. 足し算をして結果をメモリに格納する

のように、5→2→+ と言う順番で処理されます。一方、Scriptは

OP_5 OP_2 OP_ADD

のように書かれ、手順は先程と同様なので、コードの左から右に向かって処理されることがわかります。

Bitcoinにおいては、Scriptによってが、どのような条件でそのBitcoinを使用できるかということを示しています。

実際のScriptを見てみる

習うより慣れろということで、実際に最もよく使われているP2PKH(pay-to-public-key-hash)トランザクションのScriptを見てみましょう。

scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>

2行に渡って書かれていますが、上の行がトランザクションのOutputに、下の行がInputに書かれます(InputとOutputがわからない人はWikiとかその日本語版とか僕が以前書いた記事を読んで下さい)。OutputにはBitcoinをロックするロジックが、Inputにはそれをアンロックするために必要なものが書かれています。

OP_DUPとかOPなんちゃらって何。。。って感じですよね。ってことで以下に説明します。

Opcode

scriptPubKeyにある「OP_」ではじまる文字列のことを、オペコード(opcode)と呼びます。一般的なオペコードについて詳しくは知らないのですが、一つ前のスタックに対して処理のかたまりを実行するもの、なので関数とかメソッドに近いものだと理解しています(違ったら教えてください)。

それ以外にも、定数を表すオペコードもあったりします。以下に、種類ごとにオペコードを抜粋したものを載せます。

定数

word opcode hex input output Description
OP_0, OP_FALSE 0 0x00 Nothing. (empty value) An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.)
N/A 1-75 0x01-0x4b (special) data The next ''opcode'' bytes is data to be pushed onto the stack
OP_PUSHDATA1 76 0x4c (special) data The next byte contains the number of bytes to be pushed onto the stack.
OP_PUSHDATA2 77 0x4d (special) data The next two bytes contain the number of bytes to be pushed onto the stack.
OP_PUSHDATA4 78 0x4e (special) data The next four bytes contain the number of bytes to be pushed onto the stack.
OP_1NEGATE 79 0x4f Nothing. -1 The number -1 is pushed onto the stack.
OP_1, OP_TRUE 81 0x51 Nothing. 1 The number 1 is pushed onto the stack.
OP_2-OP_16 82-96 0x52-0x60 Nothing. 2-16 The number in the word name (2-16) is pushed onto the stack.

スタック

word opcode hex input output Description
OP_DUP 118 0x76 x x x Duplicates the top stack item.
OP_SWAP 124 0x7c x1 x2 x2 x1 The top two items on the stack are swapped.
OP_2DUP 110 0x6e x1 x2 x1 x2 x1 x2 Duplicates the top two stack items.
OP_3DUP 111 0x6f x1 x2 x3 x1 x2 x3 x1 x2 x3 Duplicates the top three stack items.
OP_2SWAP 114 0x72 x1 x2 x3 x4 x3 x4 x1 x2 Swaps the top two pairs of items.

暗号

word opcode hex input output Description
OP_RIPEMD160 166 0xa6 in hash The input is hashed using RIPEMD-160.
OP_SHA1 167 0xa7 in hash The input is hashed using SHA-1.
OP_SHA256 168 0xa8 in hash The input is hashed using SHA-256.
OP_HASH160 169 0xa9 in hash The input is hashed twice: first with SHA-256 and then with RIPEMD-160.
OP_HASH256 170 0xaa in hash The input is hashed two times with SHA-256.
[[OP_CHECKSIG]] 172 0xac sig pubkey True / false The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise.

ビット演算

word opcode hex input output Description
OP_EQUAL 135 0x87 x1 x2 True / false Returns 1 if the inputs are exactly equal, 0 otherwise.
OP_EQUALVERIFY 136 0x88 x1 x2 Nothing / ''fail'' Same as OP_EQUAL, but runs OP_VERIFY afterward.

P2PKHスクリプトを詳しく見てみる

pay-to-public-key-hash のスクリプトはこんなんでした。

scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>

transactionを作成するときは、以前自分に送金された未使用のtransaction output を参照するのでした。そこにはscriptPubKeyが書かれており、適当な電子署名(sig)と公開鍵(pubkey)を与えてあげればoutputがアンロックされて、Bitcoinを送金できるというわけです。

さて、実際にアンロックされる過程を見ていきます。

手順1.

<sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

utxo(unspent transaction output)のscriptPubKeyとscriptSigを連結。電子署名と公開鍵を使ってアンロックする準備。この連結したものを、左から順番にスタックに移動していき、実行していく。

手順2.

<sig> <pubKey>

2つの定数をスタックに移動。

手順3.

<sig> <pubKey> <pubKey>

手順2のOP_DUPに右から OP_DUPを作用させた。表のスタックの部分を見ると、「スタックの一番topのアイテムを複製する」と書いてある。topアイテムであるpubKeyが複製されている。

手順4.

<sig> <pubKey> <pubHashA>

OP_HASH160を右から作用させた。pubKeyのハッシュ値を計算した。

手順5.

<sig> <pubKey> <pubHashA> <pubKeyHash>

もともとアウトプットにあったpubKeyHash(ビットコインアドレスに当たる)を右に追加した。

手順6.

<sig> <pubKey>

pubKeyから計算されたpubHashA(計算結果)と、scriptPubKey にあったpubHash(答え)が等しいことが検証された(その後はスタックには残らない)。

手順7.

1

署名がチェックされた。正しかったので、1(true)が返された。

ここでtrueが返されたので、このtransactionは有効となります(マイナーによってチェックされた後、ブロックに取り込まれる)。

どうでしょう、オペコードの意味を知って、ひとつひとつ丁寧に見ていくと、意外とシンプルなことがわかると思います。

理解できなかった方も、わかりやすい参考リンクを最後に貼ったので、読んでみてください。Davide De
Rosaは特に詳しく、系統的に書かれいるのでおすすめです。

練習問題

bitFlyerさんの採用ページに手計算で解ける練習問題があるので、解いてみるとScriptをより理解できるかもしれません。この問題は、結局は3変数の連立一次方程式になります。シンプル。注意点としては、解答は16進数に変換して入力する必要があります。

参考