[bitcoin] p2pkhトランザクションを自分で組み立てる

# 環境
bitcoind v0.16
ruby v2.5
[bitcoin-ruby](https://github.com/lian/bitcoin-ruby) v0.0.18

[source code](https://github.com/kanna0000/build-bitcoin-transaction)

# これやる
ライブラリに頼らずに、bitcoin transactionをつくる方法。
p2pkhのoutputを消費します。
鍵と署名に関してはライブラリを使います。
トランザクションの構造と署名のつくりかたを主題とするので、scriptのしくみなどは省きます。
inputは1つだけのシンプルなものです。
基本的なことはやはり[mastering bitcoin/ transaction](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch06.asciidoc)がわかりやすいです。ご参考ください。
opコードのパースには[btcdeb](https://github.com/kallewoof/btcdeb)を使わせていただきます。

## 注意点
数値はlittle endianで表記。

## トランザクションの構造
トランザクションの構造に関しては、こちらの記事がとても参考になります。
[BitcoinのTransaction](https://qiita.com/tnakagawa/items/5fc1baef42a5db57e1f4)
[Bitcoin Standard Transactions（送信）](https://qiita.com/tnakagawa/items/0ee32aee500bc67cd7a4#pay-to-public-key-hash-p2pkh)
- その他参考
[Transaction/Bitcoin Wiki](https://en.bitcoin.it/wiki/Transaction)

トランザクションの例

```
0100000001dbfb811cacf55c78a49e454b017cfc10f34382c51ed98859c119aa261ba3f661000000006a47304402201ff7410c71653ab547a7ace6667f8262702d392b496c7385619f4655e5d2180d02202597db2cdd1243602f7537285c8eda21952dd2afd4c6c941f566bddc7b75d6bc01210390fc7c6a9747091ac4c94721887c7d8ccecd9ddc02aaae005138689d5c93a3affffffff0200301a1e010000001976a9144ae221ba1282464e44cd8217835fb44e92030ab288ac605af405000000001976a914d3da933dc800e1d0b2645bd3fa2616af758f571188ac00000000
```
## トランザクション(tx)を組み立てる
p2pkhのoutputを消費するtxを作ります。
`msvkJkuUpcH51VodGDXtv48z58Y1udgUKb`に20BTC送ります。
tx_inにはsignature script部分があります。
これは署名を含みます。
なにに対して署名をするかは、署名するユーザが選択することができますが、今回はスタンダードなtx全体に署名する方式(sighash all)を使います。


## input(tx_in)の作成
ここではinputのもととなるトランザクションをbitcoindでつくります。
生成されるアドレスやトランザクションはここでの例とまったく同じにはなりません。
### tx_in作成の準備
通常のアドレスを取得する

```bash
$ bitcoin-cli getnewaddress '' legacy
mkNBR5PyMTdhWtKopfSeXigS1p7QAD8f4h
```
作ったアドレスに30BTC送る。戻り値はトランザクションid

```bash
$ bitcoin-cli sendtoaddress mkNBR5PyMTdhWtKopfSeXigS1p7QAD8f4h 30
d651820a8718f83ae97fe5e6554798c069868a172477909a92460ca27fd7aa2f
```
トランザクションの内容を詳しく見る(最後に1を付け加えるのを忘れずに [^1])

```bash
$ bitcoin-cli getrawtransaction d651820a8718f83ae97fe5e6554798c069868a172477909a92460ca27fd7aa2f 1
{
  "txid": "d651820a8718f83ae97fe5e6554798c069868a172477909a92460ca27fd7aa2f",
  "hash": "d651820a8718f83ae97fe5e6554798c069868a172477909a92460ca27fd7aa2f",
  "version": 2,
  "size": 190,
  "vsize": 190,
  "weight": 760,
  "locktime": 113,
  "vin": [
    {
      "txid": "56f8d8837aceb14533b42df6f76dd5eaabffdf355d8f7fb3747b7c7568b5d6b3",
      "vout": 0,
      "scriptSig": {
        "asm": "3045022100e4410a4662ff1649c26df4c8ce76e8d9e105c082ce682558d933c9f1c263823e02206467ddb539c3f498da324eec0856071356e12f04efeb76c467330aefcc66bec0[ALL]",
        "hex": "483045022100e4410a4662ff1649c26df4c8ce76e8d9e105c082ce682558d933c9f1c263823e02206467ddb539c3f498da324eec0856071356e12f04efeb76c467330aefcc66bec001"
      },
      "sequence": 4294967294
    }
  ],
  "vout": [
    {
      "value": 30.00000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 352fd6937e24d9de927b857e5d8ea9e3a8fe8f91 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914352fd6937e24d9de927b857e5d8ea9e3a8fe8f9188ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mkNBR5PyMTdhWtKopfSeXigS1p7QAD8f4h"
        ]
      }
    },
    {
      "value": 19.99996200,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_HASH160 29ab892dc58556e7e0e8bd213e13e5b637d29bc3 OP_EQUAL",
        "hex": "a91429ab892dc58556e7e0e8bd213e13e5b637d29bc387",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "2Mw3ZBfmCUrBzBdoKtaBp8rzYr7Qtgy3TmS"
        ]
      }
    }
  ],
  "hex": "0200000001b3d6b568757c7b74b37f8f5d35dfffabead56df7f62db43345b1ce7a83d8f8560000000049483045022100e4410a4662ff1649c26df4c8ce76e8d9e105c082ce682558d933c9f1c263823e02206467ddb539c3f498da324eec0856071356e12f04efeb76c467330aefcc66bec001feffffff02005ed0b2000000001976a914352fd6937e24d9de927b857e5d8ea9e3a8fe8f9188ac288535770000000017a91429ab892dc58556e7e0e8bd213e13e5b637d29bc38771000000"
}
```

### tx_inを組み立てる
voutの1つ目をinputとして消費します。
#### previous_output
これは`outpoint`という型で、32 Byteのprevious transaction id(hash) + 4 Byteのoutput indexです[^2]。
previous transaction idはもととなるoutputが含まれるtransactionのidですので
`d651820a8718f83ae97fe5e6554798c069868a172477909a92460ca27fd7aa2f`
ただしlittle endianにするのでトランザクション内では次のように表記されます。
`2faad77fa20c46929a907724178a8669c0984755e6e57fe93af818870a8251d6`
output indexはoutputのうちなかで何番目かということです。ここでは、n:0の30BTC分のoutputを利用するので
`0x00000000`
となります。
もし1の場合はlittle endienに注意して
`0x01000000`
となります。
#### script size
まだスクリプトのサイズはわからないので保留です。
#### signature script(unlocking script)
署名がここに含まれるのですが、tx全体に対して署名をしたいです(sighash all)。 
署名するときにはまだ存在しない署名欄(まさにこの部分=script signature)はどうすればよいのでしょうか[^3]。
p2pkhの場合、前トランザクションのscript pubkeyを一時的に当てはめておきます。
署名をするには、txの他の部分(tx_outなど)を組み立てる必要がありますので、tx_outも組み立ててから署名をしていきます。
#### sequence
通常`ffffffff`の4Byteです。
いまのところ`ffffffff`以外について私はわかりません。

## outputの作成
#### value
送金量です。satoshiで表現し8Byteの16進数のlittle endienです。
20BTC送るので
`0094357700000000`

#### pubkey script size
pubkey script（次項目）のバイト長は25 Byteですので、16進数にして
`19`

#### pubkey script
今回はp2pkh宛で、以下のようにします。
`76a91488217c4b26f9221e162fd43a919759e30069db3788ac`
opコードにすると(by [btcdeb](https://github.com/kallewoof/btcdeb))

```
script                                    
-----------------------------------------
OP_DUP                                    
OP_HASH160                                
88217c4b26f9221e162fd43a919759e30069db37 
OP_EQUALVERIFY                            
OP_CHECKSIG                              
```

## tx全体
これまでつくったtx_inとtx_outをつかって完全な形式に整えます。

```
version: 01000000
tx_in_count: 01
(tx_in)
(outpoint)
prev_txid: 2faad77fa20c46929a907724178a8669c0984755e6e57fe93af818870a8251d6
prev_output_index: 00000000
script_size: 19
script_sig: 76a914352fd6937e24d9de927b857e5d8ea9e3a8fe8f9188ac
sequence: ffffffff
tx_out_count: 01
(tx_out)
value: 0094357700000000
script_size: 19
script_pubkye: 76a91488217c4b26f9221e162fd43a919759e30069db3788ac
```
```
01000000012faad77fa20c46929a907724178a8669c0984755e6e57fe93af818870a8251d6000000001976a914352fd6937e24d9de927b857e5d8ea9e3a8fe8f9188acffffffff0100943577000000001976a91488217c4b26f9221e162fd43a919759e30069db3788ac
```

## 署名
以上のデータに4 Byteのsighash type(little endien)を付け加えて、sha256を二回適用したものに署名します。
今回はsighash allなので`0x01000000`
したがって署名の対称のもととなるデータは以下です。

```
01000000012faad77fa20c46929a907724178a8669c0984755e6e57fe93af818870a8251d6000000001976a914352fd6937e24d9de927b857e5d8ea9e3a8fe8f9188acffffffff0100943577000000001976a91488217c4b26f9221e162fd43a919759e30069db3788ac01000000
```
以上を`payload`としてsha256を二回。

```ruby:double_sha256
# double hash payload
# @param payload [string] hex string
# @return [string] hex string
def double_sha256 payload
  OpenSSL::Digest::SHA256.hexdigest([OpenSSL::Digest::SHA256.hexdigest([payload].pack("H*"))].pack("H*"))
end
```
この結果は、同じpayloadに対しては常に同じ値となり、バイト長は32 Byteです。
`3dc985affd7075acd5655de9170d51076e7fb4f80535b059a5b0c5b4e19e0775`
このdouble_sha256の戻り値(target)に対して対応する秘密鍵でECDSA署名を行います。
bitcoinにおける"署名"は、ECDSA署名にsighash typeの1Byte分を付け加えたものになります。
sighash_allであれば、`0x01`を付加します。


```ruby:sign_sample
# make signature
# @param data [string] hex string
# @return [Signature]
def sign data
  sigobj = OpenSSL::PKey::EC.new('secp256k1')
  sigobj.private_key = OpenSSL::BN.new(@priv_key, 16)
  signature = sigobj.dsa_sign_asn1([data].pack("H*")).unpack("H*")
  @signature = signature[0] + @sighash
  self
end
```
署名に関してはいくつか注意点があります。
同じデータに対して署名をしても、署名値は毎回異なります。
ECDSA署名では署名時にランダムな値を利用しているためです[^4]。
署名はDER形式でなければなりません。
DER形式については[BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)で定義されています。  
ECDSA署名のSのサイズに制限があります。
大きすぎるとエラーで教えてくれます。事前にチェックしておきましょう。
Low S valueについては[BIP62](https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki)で定義されています。
また、Sのサイズを自分で変更した際には、DER形式でのSサイズおよび署名全体のサイズ部分も変えなければいけないので注意してください。  
この署名をinputのsignature script部分に入れてトランザクションの完成です。

コード全体は[github](https://github.com/kanna0000/build-bitcoin-transaction)にあるのでよければ参考に（なるのか？）してください。



# もっとくわしく！
[mastering bitcoin](https://github.com/bitcoinbook/bitcoinbook)
[Transaction/Bitcoin Wiki](https://en.bitcoin.it/wiki/Transaction)
[BIP62](https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki)
[BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)
[^1]: [getrawtransaction (0.16.0 RPC)](https://bitcoincore.org/en/doc/0.16.0/rpc/rawtransactions/getrawtransaction/)
[^2]: [outpoint](https://bitcoin.org/en/glossary/outpoint)
[^3]: [TxIn: A Transaction Input (Non-Coinbase)](https://bitcoin.org/en/developer-reference#txin)
[^4]: [The Importance of Randomness in Signatures/ Mastering Bitcoin](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch06.asciidoc#the-importance-of-randomness-in-signatures)