btc: miniscript
2025/03/07
はじめに
昨日から開発日記よりもまとめ記事を優先するようにした。
日記だとね、記事の品質が低いといって Google がインデックスに登録してくれないのだよ。。。
そう言われたわけではないのだけど、まずは内容が重たいページを増やしていこう。
日記の方はインデックス登録を諦め、日記のままにする。
今日は miniscript の調査だ。
miniscript
Miniscript is a language for writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, generic signing and more.
Bitcoin スクリプトを構造的に書くための言語だ。
まあよく使うスクリプトであればそんなに間違えないのだけど、
スタックに載せる数値を書き間違えるということはありそうだ。
もしそういうスクリプトに支払ってしまうと取り戻せないのだ。
それを避けるには、事前に regtest などで実験しておくくらいしかやりようがない。 先にアドレスを作って送金をするので、confirm されたら confirm してしまうのだ。
固定のスクリプトだったらまだよいけど、プログラム中でスクリプトを自作するタイプだとなかなか怖い。
安心できるコンパイラがあるとうれしい。
ということかどうかは知らないが、
動かす
ビルド。
$ git clone https://github.com/sipa/miniscript.git
$ cd miniscript
$ make
サンプルのスクリプトを与えてみる。
これはコンパイルするルートを通ったときで、順番にこうなっているはず(変数名や関数名より)
- スクリプトサイズ + 平均コスト: 256.9000000000
- スクリプトサイズ: 114
- 略称:
and_v(or_c(pk(B),or_c(pk(C),v:older(1000))),pk(A))
- 元の文字列:
and(pk(A),or(pk(B),or(9@pk(C),older(1000))))
$ echo "and(pk(A),or(pk(B),or(9@pk(C),older(1000))))" | ./miniscript
X 256.9000000000 114 and_v(or_c(pk(B),or_c(pk(C),v:older(1000))),pk(A)) and(pk(A),or(pk(B),or(9@pk(C),older(1000))))
さっぱりわからん。。
ホームページではコンパイルするとOPコードっぽいものを吐き出しているのだが。
最初からテキストボックスに入っていたスクリプトは難しいので、載っているサンプルにしよう。
A single key
公開鍵 key_1
が 1つだけ。
pk(key_1)
コンパイル
X 108.0000000000 35 pk(key_1) pk(key_1)
main.cpp の run()
に出てくる最初の if
文をちょっと変更すると逆アセンブルされたスクリプトが出力された。
auto str = ret->ToScript(COMPILER_CTX);
printf("X total_cost=%17.10f\nscript_size=%5i\n%s\ninput=%s\n",
ret->ScriptSize() + avgcost,
(int)ret->ScriptSize(),
Disassemble(str).c_str(),
line.c_str());
$ echo "pk(key_1)" | ./miniscript
X total_cost= 108.0000000000
script_size= 35
<key_1> OP_CHECKSIG
input=pk(key_1)
ToScript()
を使って Disassemble()
で出力したらこうなった。
見つけたのは偶然だ。が compiler.h Abbreviate()
の近くにあったおかげだな。
関数名が分かればそこから検索すれば良い。
js_bindings.cpp の関数が index.html が呼び出している関数なのだろう。
しかし、これはどう使うとよいのだろうか。
key_1
の代わりに 33バイトの公開鍵を入れてみたがエラーになる。
長さが 16文字までなので、そういう使い方ではないのだ。
イメージとしては、文字列などで miniscript のスクリプトを書いてコンパイルすると Bitcoinスクリプトになるというものだった。
そういう使い方もできるのかもしれないが、よくわからんなー。
Rust のもあるし、用例を探してみるか。
おわりに
もうちょっとやらねばならんな。
おまけ
lto-wrapper
miniscript を clone して make
しただけなのだが warning が出てきた。
lto-wrapper: warning: using serial compilation of 3 LTRANS jobs
lto-wrapper は g++
の verbose にちょろっと出てくる。
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
...
...
stackoverflow には Link Time Optimization と説明があった。
WebAssembly?
Makefile を見ると em++
でコンパイルすると JavaScript 版ができそうだった。
私の環境にはインストールされていなかったが emscripten
というものらしい。
有名だが私のまったく知識がない WebAssembly というやつだった。
心配だったので検索したが、WebAssembly の略称は Wasm でよかった。
先頭は大文字だ。Firefox と同じルールかもしれん。