Mastering Bitcoin Script

# Mastering Bitcoin Script

2年ほど前に書いた記事を発掘したので今更公開する。
詳しくは参考文献である「ブロックチェーン・プログラミング　仮想通貨入門」を読んでみるのがいい。
https://www.amazon.co.jp/dp/B078G94JNT/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1



## 前提
![](https://i.imgur.com/HSxDaxK.png)
※[(出典) Segwitに関して調べた記録2](https://cryptocurrency.muragon.com/entry/4.html)

```
 ScriptSig(unlocking script) + ScriptPubkey(locking script)
```
新しくTransactionを作成する際、UTXOのTransaxtionをTxと解除用スクリプトと共に指定、アウトプットをロックするスクリプトを指定。
検証の順序はScriptSig実行してからScriptPubkeyを実行。

#### ScriptSig
Transactionのインプットに置かれている署名用スクリプト。

#### ScriptPubkey
Transactionのアウトプットに置かれている解除条件スクリプト。


## bitcoindコードリーディング
### /src/script/interpreter.cpp EvalScript関数
https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp

C++スタンダードライブラリの[vector](https://cpprefjp.github.io/reference/vector/vector.html)を使いstackの操作を処理。

コードリーディングした時のメモ:
https://hackmd.io/@Tokashi/SJx9rLXVv
 

## OP_codeの特徴
* チューリング不完全でステートレスな言語。
* スタックベースで左から右へ処理。

## OP_codeの要件
* スクリプトが終了したときにスタックの先頭の項目がTrue（ゼロではない）であれば、トランザクションは有効。0が残った場合、複数のスタックが残った場合、スタックがからの場合は検証に失敗する。
 -> Transactionの検証をし、失敗させるOP_codeを使う。
* スタック上のバイトベクトルの長さの上限は520バイト。
* 整数やブールをスタックから取り出すオペコードは4 バイト以下。
* 加算や減算はオーバーフローして 5 バイトの整数がスタックに置かれることもある。


## 例

![](https://i.imgur.com/MK12N92.png)
```
2 3 OP_ADD 5 OP_EQUAL
```

## IDE
一度自分で触ってみて欲しい。
* Bitcoin IDE
https://siminchen.github.io/bitcoinIDE/build/editor.html
 
* Bitauth IDE
https://ide.bitauth.com/


## よく使うOP_code
### OP_ADD
![](https://i.imgur.com/sTF15N2.png)

スタックの上から2番目と先頭を足す。
(例)
```
1 2 OP_ADD => 0x3
```

### OP_SUB
![](https://i.imgur.com/UoYIWIS.png)

スタックの上から2番目から先頭を引く。
```
2 1 OP_SUB => 0x1
```

### OP_DUP
![](https://i.imgur.com/LBSyMvY.png)

先頭スタックを複製。
```
2 OP_DUP => 0x2 0x2
```

### OP_EQUAL
![](https://i.imgur.com/0I57Nir.png)

上から2番目スタックと先頭のスタックが同じなら１を返す。違うなら0を返す。
```
2 OP_DUP OP_EQUAL => 0x1
```


### OP_VERIFY

先頭のスタックがTrueでない場合、Transactionの検証に失敗する。
先頭スタックは削除される。
```
2 1 OP_EQUAL op_verify => Execution unsuccessful
```

### OP_EQUALVERIFY

OP_EQUAL実行後、OP_VERIFYを実行。

### 0P_HASH160

先頭スタックをSHA-256 -> RIPEMD-160する。
```
<Pubkey> OP_HASH160 => <Pubkey Hash>
```

### OP_CHECKSIG
![](https://i.imgur.com/RPS3oDU.png)
スタックを全てハッシュ化する。スタックが署名と署名に対応した公開鍵だった場合１を返す。違う場合0を返す。

### OP_CHECKMULTISIG


### OP_IF・OP_ELSE・OP_ENDIF
先頭のスタックがTrue(０でない値)だった場合、OP_IFのスクリプトを実行。先頭スタックは削除される。

```
1 2 OP_EQUAL        // false
OP_IF
　<PUBKEY> OP_HASH160 OP_EQUAL       // 実行されない
OP_ELSE
　<PUBKEY> OP_HASH160 OP_DUP OP_EQUAL   // 実行される
OP_ENDIF
```

### OP_CHECKMULTISIGVERIFY
OP_CHECKMULTISIG実行後、OP_VERIFYを実行。

### OP_DROP
先頭のスタックを削除する。

### OP_RETURN
関係のないデータをブロックチェーン上に残すためのOP_code。拡張によく使われる。
検証時OP_RETURNがあった場合即座にtransactionの検証を無効にする。
OP_RETURNアウトプットはunlocking scriptが無く永久に使えない。
dataの上限サイズは80byte。

```
 OP_RETURN <data>
```


### OP_CHECKSEQUENCEVERIFY
入力の相対ロック時間が先頭スタックの値と同じかそれより短い場合Transactionの検証に失敗する。

まだまだ色々ある。詳しくは[Bitcoin Wiki](https://en.bitcoin.it/wiki/Script)に載っている。


## 一般的なTransactionに使われるOP_code
### P2PKH(Pay to Public Key Hash)
![](https://i.imgur.com/HFGKVbi.png)


一番シンプルな送金トランザクション。

*ScriptPubkey*
```
OP_DUP OP_HASH160 <pubkey Hash> OP_EQUALVERYFY OP_CHECKSIG
```

*ScriptSig*
```
<signature A> <pubkey A>
```

### P2SH(Pay to Script Hash)
マルチシグトランザクション。

P2SHはスクリプトが長くなってしまうため、scriptPubkeyにreedem scriptのハッシュを入れておき、sicriptSigでreedem scriptを提示する。

*ScriptPubkey*
```
OP_HASH160 <redeem script hash> OP_EQUAL
```

*ScriptSig*
```
OP_0 <signature A> <signature B> <reedem script>
```

*redeem script*
```
2 <pubkey A> <pubkey B> <pubkey C> 3 OP_CHECKMULTISIG
```

## Segwit Transactionに使われるOP_code
### segwit(segregate witness)
今までのTransactionはscriptSigの改ざんができた([malleability問題](https://en.bitcoin.it/wiki/Transaction_malleability))ため、トランザクションのインプットから署名を分離し、witnessの領域に移動させた。(一番上の図を参照。)

これにより、TXIDを作成するために必要だったトランザクションの領域が未署名な状態でも確定するため、未署名のトランザクションをInputに指定することができるようになった。

### P2WPKH(Pay to Witness Public Key Hash)
Segwitバージョンの送金トランザクション。

*ScriptPubkey*
```
0 <20-byte pubkey hash>
```

*ScriptSig*
```
(空)
```

*witness*
```
<signature A> <pubkey A>
```

### P2WSH(Pay to Public Key Hash)
Segwitバージョンの送金トランザクション。
*ScriptPubkey*
```
0 <32-byte redeem script hash>
```

*ScriptSig*
```
(空)
```

*witness*
```
<A value that meets redeem's unlocking criteria> <redeem script>
```

#### 2-of-2マルチシグスクリプトの場合
*ScriptPubkey*
```
0 <32-byte redeem script hash>
```

*ScriptSig*
```
(空)
```

*witness*
```
0 <signature A> <signature B> <redeem script>
```

*redeem script*
```
2 <Pubkey A> <Pubkey B> 2 OP_CHECKMULTISIG
```


## 発展的なBitcoin Script
複雑なBitcoin Scriptを書くことでBitcoinを拡張して使うことができる。
拡張にはロックタイムをよく用いる。まずは、ロックタイム関連のOP_codeを説明する。
また、一般的なトランザクションではあまり用いられないため、上では紹介しなかったOP_SWAP、OP_SIZEも説明する。


### OP_CHECKLOCKTIMEVERIFY
2016年6月に[BIP-69](https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki)として提案された。
先頭スタックがトランザクションのnLockTimeフィールドよりも大きい場合、トランザクションの検証に失敗する。
以下の場合にも検証に失敗する。
* 先頭スタックが空、０または負の値
* インプットのnSequenceの値が0xffffffff
* 先頭スタックが500000000以上でnLockTimeが500000000未満の時。間やその逆の場合。

OP_CHECKLOCKTIMEVERIFYの実行後引数はスタックに残るのでOP_DROPの使用を推奨。

### OP_CHECKSEQUENCEVERIFY
2015年8月に[BIP-112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)として提案された。
指定した相対時間(使用するトランザクションがブロックに取り込まれてからの経過時間)までトランザクションをロックする。
ビットが設定されている場合512秒単位の時間で、そうで無い場合ブロック高として解釈。unlockする際はトランザクションのnSequenceに解除期間を指定。

### OP_SWAP
![](https://i.imgur.com/nZ6XzaV.png)

先頭から2このスタックの順序を逆転させる。

### OP_SIZE
![](https://i.imgur.com/0FtdqXi.png)
先頭スタックの文字列の長さを追加する。


## 参考文献
*「ブロックチェーン・プログラミング　仮想通貨入門」,  講談社, 著：山崎重一郎, 安土茂亨, 田中俊太郎, 2017年08月22日
https://www.amazon.co.jp/dp/B078G94JNT/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

*「Mastering Bitcoin 」
https://github.com/bitcoinbook/bitcoinbook/blob/develop/preface.asciidoc

* Script - Bitcoin Wiki :
 https://en.bitcoin.it/wiki/Script

* Transaction - Bitcoin Wiki :
 https://en.bitcoin.it/wiki/Script