hiro99ma blog

Something technical

btc: miniscript

2025/03/07

はじめに

昨日から開発日記よりもまとめ記事を優先するようにした。
日記だとね、記事の品質が低いといって Google がインデックスに登録してくれないのだよ。。。
そう言われたわけではないのだけど、まずは内容が重たいページを増やしていこう。 日記の方はインデックス登録を諦め、日記のままにする。

今日は miniscript の調査だ。

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

サンプルのスクリプトを与えてみる。
これはコンパイルするルートを通ったときで、順番にこうなっているはず(変数名や関数名より)

$ 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 と同じルールかもしれん。


 < Top page


コメント(Google Formへ飛びます)

GitHub

X/Twitter

Homepage