Develop with pleasure!

福岡でCloudとかBlockchainとか。

witnessデータを含むブロックのwitness rootとcommitment hashの計算

Segwitの導入にあたってブロック作成時にwitness トランザクションの署名が確かにブロックに含まれていることを保証するために新しいCommitment構造が導入されている。

techmedia-think.hatenablog.com

コインベーストランザクションに追加されたCommitmentのデータ構造

ブロック作成時に作られるコインベーストランザクションにそのCommitmentデータが新しく追加されているので、実際にどう変わったのか見てみる。

↓がtestnetで確認できたwitnessなトランザクションを含むブロックのコインベーストランザクション

{
  "hex": "010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603cbd20e00048681fc5704bacfd5370cc69bfb57b25c0000000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02c0eba012000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e330120000000000000000000000000000000000000000000000000000000000000000000000000",
  "txid": "f5b1b47c99ab40fa765582dae0f4346eecbe9b77ce99c66bc765378d315441f3",
  "hash": "944c9305710c116ddccec64762ed642315e48a7c279c36e11756b74c8c5984e7",
  "size": 222,
  "vsize": 195,
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "03cbd20e00048681fc5704bacfd5370cc69bfb57b25c0000000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542f",
      "txinwitness": [
        "0000000000000000000000000000000000000000000000000000000000000000"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 3.12536000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d6 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mss5NFyX96ix4erFMamR1gK3SsvUSMWcjE"
        ]
      }
    }, 
    {
      "value": 0.00000000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_RETURN aa21a9ed670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e33",
        "hex": "6a24aa21a9ed670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e33",
        "type": "nulldata"
      }
    }
  ],
  "blockhash": "000000000000002b2fcf202c54a21cf792a66592a4f8b655b026f5e3d419d656",
  "confirmations": 15,
  "time": 1476170550,
  "blocktime": 1476170550
}

Commitmentの追加

出力を見ると今までのコインベーストランザクションには無かったOP_RETURNを含む出力が追加されているのが分かる。Segwitでは新たにcommitment用のデータフィールドを設けるのではなく、OP_RETURNを使うことでcommitmentのデータ領域を確保している。

"asm": "OP_RETURN aa21a9ed670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e33",
"hex": "6a24aa21a9ed670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e33",

このcommitmentデータは以下のような内容で構成されている。

バイト数 内容
1 0x6a OP_RETURN
1 0x24 36バイト(0x24)のデータを続いてプッシュする
4 0xaa21a9ed commitmentヘッダ
32 67043...78e33 commitment hash=Double-SHA256(witness root hash|witness reserved value)
39バイト目以降 コンセンサスとは関係ない任意のデータ(オプション)

witnessなトランザクションの署名がブロックチェーンに記録されていることを確認するためブロック内の全てのwitnessを含むデータからマークルツリーが作られていて、そのマークルルートがwitness rootになり、commitment hashの計算に使われている。
(従来のトランザクションのマークルツリーはtxidを元に計算されているのでwitnessデータは含まれない)

※ ブロック内のトランザクションが全てwitnessなトランザクションではない場合、commitmentはオプションとなる。

では、実際witness rootとコミットメントハッシュはどのように計算されているのか?

witness rootとcommitment hashの計算

witness rootはwtxid*1のデータから計算されている

Bitcoin Coreで実際にwitness rootを計算しているのは、merkle.cppの↓の部分

uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
{
    std::vector<uint256> leaves;
    leaves.resize(block.vtx.size());
    leaves[0].SetNull(); // The witness hash of the coinbase is 0.
    for (size_t s = 1; s < block.vtx.size(); s++) {
        leaves[s] = block.vtx[s].GetWitnessHash();
    }
    return ComputeMerkleRoot(leaves, mutated);
}

コインベースの場合はそれ自身が有効なwitnessデータを持たないので、コインベースのwtxidはwitness reserved valueの値で構成され、現在は0x00...00となる。

こうして算出したwitness rootwitness reserved valueを付加してSHA256ダブルハッシュしたのがcommitment hashになる。

bitcoin-rubyで↑のコインベーストランザクションを含むブロックのwitness rootcommitment hashを計算したのが↓

witness rootを計算する際にwtxidのエンディアンを変換しておく必要がある。

実行すると

witness_root = 50187168cf7fb4fa39db8fadefb032fb28e109bf22732a589144f108276945f4
commitment = 670436c55de638c8100326d72998157a61aab2af1a8d4c5785f9093134b78e33

となり、コインベーストランザクションcommitment hashと同じ値になっているのが分かる。

*1:従来のtxidの計算にはwitnessデータは含まれないのに対し、witnessデータを含めて計算したハッシュ値。具体的な計算内容はBIP-144内で定義。