OP_CHECKSIG の仕様
電子署名を作るには、OP_CHECKSIG の仕様を知る必要があります。
...とはいえ、実際に使われているパターンは1つしかないので、
それだけ覚えてもらえれば十分です。
bitcoin wiki の OP_CHECKSIG
ページに図と共に詳細な説明がありますが、もう少し噛み砕いて説明します。
- まず、UTXO の scriptPubKey を取り出します。
- 新規トランザクションの scriptPubKey を設計します。
- 次に、新規トランザクションの scriptSig を全部空っぽ、長さは 0 にしたデータを作ります。
- 電子署名を作る対象の入力データだけ、scriptSig の部分に、取り出した scriptPubKey を挿入します。
- この状態のデータの SHA256 ハッシュを2度計算して、電子署名を作成します。
具体的には図のように作ります。
電子署名は scriptSig ごとに作る必要があるため、
入力が複数ある場合はこのようになります。
さて、それでは実際に作ってみましょう。
今回は monacoin のテストネットで実験してみます。
自分から自分に送る単純なトランザクションです。
UTXO の scriptPubKey
P2PKH を使っているなら以下の形式で固定です。
76 ... OP_DUP A9 ... OP_HASH160 14 ... 公開鍵のハッシュの長さ (PUSH 命令) DB 2E 05 4B B5 76 DC 63 28 3C 00 60 AB D4 6D F1 40 57 C2 DE ... 公開鍵のハッシュ 88 ... OP_EQUALVERIFY AC ... OP_CHECKSIG
長さは 25Byte です。
新規トランザクションの scriptPubKey
P2PKH で出力するなら先ほどと同じです。
76 ... OP_DUP A9 ... OP_HASH160 14 ... 公開鍵のハッシュの長さ (PUSH 命令) DB 2E 05 4B B5 76 DC 63 28 3C 00 60 AB D4 6D F1 40 57 C2 DE ... 公開鍵のハッシュ 88 ... OP_EQUALVERIFY AC ... OP_CHECKSIG
長さも同じく 25Byte です。
新規トランザクションの準備
第3回で説明した通りに scriptSig を空っぽの状態で raw トランザクションを作ります。
02 00 00 00 ... バージョン 2 01 ... 入力は 1 つ 入力データ 82 82 9E 2C 9E F9 81 BA 16 63 42 86 AB 9C 6F F2 1B E0 44 AE BA FB 77 30 81 F5 EE 31 46 B0 7A C3 ... 前 TXID: c37ab04631eef5813077fbbaae44e01bf26f9cab86426316ba81f99e2c9e8282 00 00 00 00 ... 前 TX の第0出力を使用する 00 ... scriptSig は 0 Byte 00 00 00 00 ... シーケンス番号はとりあえず 0 01 ... 出力は 1 つ 出力データ C0 9E E6 05 00 00 00 00 ... 0.99 tMONA 19 ... scriptPubKey は 25 Byte 76 A9 14 DB 2E 05 4B B5 76 DC 63 28 3C 00 60 AB D4 6D F1 40 57 C2 DE 88 AC ... scriptPubKey 本体 00 00 00 00 ... ロックタイムはとりあえず 0
電子署名対象となる入力だけ、scriptSig を埋める
同じなので区別がつきづらいですが、
前トランザクションから抽出した scriptPubKey を、
scriptSig を埋めるべき場所に配置します。
そして末尾に 01 00 00 00 をくっつけます。
02 00 00 00 ... バージョン 2 01 ... 入力は 1 つ 入力データ 82 82 9E 2C 9E F9 81 BA 16 63 42 86 AB 9C 6F F2 1B E0 44 AE BA FB 77 30 81 F5 EE 31 46 B0 7A C3 ... 前 TXID: c37ab04631eef5813077fbbaae44e01bf26f9cab86426316ba81f99e2c9e8282 00 00 00 00 ... 前 TX の第0出力を使用する 19 ... scriptSig ではなく前トランザクションの scriptPubKey の長さは 25 Byte 76 A9 14 DB 2E 05 4B B5 76 DC 63 28 3C 00 60 AB D4 6D F1 40 57 C2 DE 88 AC ... 前トランザクションの scriptPubKey 本体 00 00 00 00 ... シーケンス番号はとりあえず 0 01 ... 出力は 1 つ 出力データ C0 9E E6 05 00 00 00 00 ... 0.99 tMONA 19 ... scriptPubKey は 25 Byte 76 A9 14 DB 2E 05 4B B5 76 DC 63 28 3C 00 60 AB D4 6D F1 40 57 C2 DE 88 AC ... scriptPubKey 本体 00 00 00 00 ... ロックタイムはとりあえず 0 01 00 00 00 ... くっつける
SHA256 ハッシュを2度計算して電子署名を作成する
うまく整形してバイナリ形式で openssl に流し込みます。
openssl dgst で1回 sha256 を計算するので、先に一度 sha256 を計算しておく必要があることに注意してください。
$ printf "%b" "\x02\x00\x00\x00\x01\x82\x82\x9E\x2C\x9E\xF9\x81\xBA\x16\x63\x42\x86\xAB\x9C\x6F\xF2\x1B\xE0\x44\xAE\xBA\xFB\x77\x30\x81\xF5\xEE\x31\x46\xB0\x7A\xC3\x00\x00\x00\x00\x19\x76\xA9\x14\xDB\x2E\x05\x4B\xB5\x76\xDC\x63\x28\x3C\x00\x60\xAB\xD4\x6D\xF1\x40\x57\xC2\xDE\x88\xAC\x00\x00\x00\x00\x01\xC0\x9E\xE6\x05\x00\x00\x00\x00\x19\x76\xA9\x14\xDB\x2E\x05\x4B\xB5\x76\xDC\x63\x28\x3C\x00\x60\xAB\xD4\x6D\xF1\x40\x57\xC2\xDE\x88\xAC\x00\x00\x00\x00\x01\x00\x00\x00" | openssl sha -sha256 -binary | openssl dgst -sha256 -sign wallet.pem -hex (stdin)= 304402205c66d2c6f1ae9d91d4103f4f40b726cc9c272142b1a17fceb5237445fdbd9563022021f12c9da77eac953531616ee673dc1969a048c3c16aeb6022e0d2e8cad3e64f
これで、電子署名は完成です。
電子署名は乱数を使用するため毎回異なる署名が出力されます。
今は詳しく説明しませんが、正規化ルールの都合があるので、
何度か実行して 3044 から始まるものを選んでください。
今回はここまで。
ご質問、ご意見等ありましたらお気軽にリプライください。