P2TRからredeemする(script編)
前回、P2TRのkeypathからredeemした。
今回はscriptpathからgolangでredeemするプログラムについて書いていく。
全然関係ないが、taprootは主根や直根の意味だそうだ。例としてニンジンがよく挙げられていた。ならば大根やゴボウもそうなのだろうか。スクリプトを分岐して生やすからそうなったのだろうか? しかしleafとして表現しているので枝っぽい名前の方がよかったんじゃなかろうかと思わなくもないが、植物に詳しくないので考えるのはやめておこう。
P2TRの場合、スクリプトで解くときには全部のスクリプトを載せる必要がない。P2SHやP2WSHでは全部載せていたので解いてしまえばどういうスクリプトだったのか確認できるのだが、P2TRでは全貌が分からない。
より不要な情報を公開する必要がなくなったと言えるが、学習する方としては実例での確認がしづらくなった。
見本がほしかったので、こちらのサイトを参考にして作った。いろいろ削除して、golangのプログラムと同じような構成にした程度だ。
まずわかったのは、スクリプトを分解しなくてはならないということだった。BIP-341にはどちらでもよさそうなことは書いてあったが、分岐がある場合は通常分解するということも書いてあったのでそうしておく。これはスクリプトデバッガ btcdeb のドキュメントだが最初の方にスクリプトの書き換えが載っている。
P2SHなどではOP_ELSEのルートにするために意味の無いデータをスタックに積むことがあるのだが、どのleafのスクリプトで解くのかを示せば済むことになる。
分解したらtreeにする。BIP-341では複数段になっているが、そういう難しいスクリプトが思いつかなかったので分岐が1箇所だけになった。
今回はredeemするなら左のスクリプトか右のスクリプトかのどちらかになる。サンプルコードは左のスクリプト(コード中は script1
)から解くようにしている。
P2WSHならこういうwitnessスタックになる。
P2TRのscriptpathの場合、witnessスタックの最後にcontrol blockというものが必要になる。
BIP-341 ではスクリプトDを使う場合が書かれている。
スクリプトDはwitnessスタックに載せるので、それ以外の上に向かって計算するのに必要な相手を順番に列挙する。一番上はinternal keyが相手になるので最初の要素はinternal keyになる。1バイト目はleaf versionとパリティビットになっている。今はleaf versionが 0xc0(192)だそうだ。先頭7bitではなく先頭のバイトを 0xfe
と論理積を取った値がleaf versionと呼ぶようになっているそうだ。
btcdライブラリでは txscript.AssembleTaprootScriptTree() で IndexedTapScriptTree
を作ることができるようだ。そこからTapscriptProof.ToControlBlock() で control block を作ることができた。今回はスクリプトのインデックス値を直接0と書いたが、lndのコードを見ると LeafProofIndex[]
取得するのがよさそうだ。
もう少し難しいスクリプトも試してみないといかんが、実装の方向性としては間違えていないと思う。
btcdライブラリは interface/struct
やメソッドが多くつらかった。他のライブラリも探してはみたのだが、どうにも見つけられない。BDKをライブラリとして使うという手段はありそうだが、そちらは調べていない。