暗号通貨に関する事など

暗号通貨に関する覚書など。メモや日記。

※技術的なことに関して、間違っていたらコメントから指摘していただけると泣いて喜びます

Segwitに関して調べた記録2


前回の続き



2,トランザクションと新たに追加されるWitnessという構造に関して

 これを書かないと始まらないので、いきなりになるが構造に関して書こうと思う。今までのトランザクションの構造を知っているものとして書くので、わからない方は

 Transaction - Bitcoin Wiki

 (“general format of a Bitcoin transaction (inside a block)”以下の部分)

を見よう。



トランザクションとWitnessの構造

 トランザクションとWitnessの構造に関して文字で書いて伝える自信もないので、新旧対比を図にして載せる。文字が小さくてごめんね。

 (※tx_outの数が2つあった間違いを修正しました)


 赤色に着色された箇所がSegwitで新たに追加されるフィールドだ。赤色着色部の一番下、Witnessの部分が今までのトランザクションとは別に保管される場所であるWitnessの本体である。(特に理由はないが、tx_in,tx_outは2個ずつのパターンで書いた)
 以下、新たに追加されるmaker、flag、witnessの部分について書く。



maker

 makerは1byteのフィールドで、必ず「0x00」に固定される。
 何故このフィールドを追加して必ず「0x00」で固定するのかというと、後方互換のためである。


 makerがセットされている位置は旧トランザクションでは「tx_inの数」となっている。Segwit非対応のクライアントがSegwit形式のトランザクションを受け取った時に「これはtx_inの数が0個となっているので、つまり何もない空のトランザクションだ」と判断してくれるので、makerを0にセットしておけば意図しない形のトランザクションとして読み込まれるようなことがない。makerフィールドを新たに設けて0x00をセットするのはそのためだ。


 また、Segwit対応のクライアントはここを見てこのトランザクションがSegwit形式か旧形式かを見分けることができる。



flag

 flagは1byteのフィールドで0以外をセットするフィールドとされている。正直、これの使いみちはまだ良く分かっていないのだが、トランザクションの作用に影響を与えないフラグのようなものだと理解している。(間違ってたらごめんなさい)



Witness

 Witnessは署名検証に使われる構造体で、参照先のロックスクリプトがP2WPKHまたはP2WSHの時に対応することになる。ここで注意しておきたいのが、Witnessはビットコインスクリプトとは違う構造体であり、ここにビットコインスクリプトを書いて入れておくわけではない。


 Witnessはスタックデータの数を示すvar_int(compact size uint などと書かれることもある1-9byteで数を表すバイト配列)から始まり、その後ろにvar_intで指定した数のスタックデータがつく。スタックデータの頭にはスタックデータの長さを示すvar_intがつけられる。
 
 詰まるところ、下記図のようなデータが格納されることになる。
 (図はStackDataの数が2個の場合)

 これが、Witnessプログラムに読み込まれて、署名検証として利用される。なお、Witness内でインデックスがレガシーなP2PKHスクリプトに対応するとき(署名にwitnessを利用しないパートが現れた時)は、"0x00(スタックデータ無し)"としておく。


 繰り返しになるが、これはビットコインスクリプトとは別の構造体になるので、stackDataの長さを示すのはvar_intであってビットコインスクリプトのPUSH_DATAコマンドではない。また、スクリプトではないので520byteの制限も受けない。



tx_idとwitness_idについて

 この記事の次にトランザクション展性について書こうと思っているが、その予備知識として、tx_idとwitness_idについて知っておかなくてはならない。


 Segwit導入後も、tx_idを計算するときに使う要素は旧トランザクションのそれをそのまま利用する。つまり、新しくSegwitで追加されたmaker、flag、witnessは、Segwit導入後もtx_idを計算するのには利用されない。


 代わりに、witness_idと呼ばれるものが追加され、その計算は、上記に示したSegwitトランザクションをまるまるシリアライズしたものをSHA-256doubleHashして導かれる。


 詳しくはまた別の機会に書くが、tx_idの計算にwitnessのデータを含めないということはつまり、witnessの中身を変更してもtx_idの値は変わらないということになるので、今までのように「署名用スクリプトを同じ意味になるように書き換える」というトランザクション展性攻撃が出来なくなる。



Segwitとトランザクションの構造に関しての説明は以上でおわり。
〜3へ続く〜

Segwitに関して調べた記録3



前回の続き


3,Segwitとトランザクション展性攻撃耐性に関して

 Segwitがもたらしてくれる恩恵として「トランザクション展性攻撃の耐性が増す」ということをよく言われ、それがライトニングネットワークを実現するのに必要だと言われている。



トランザクション展性攻撃(はじめに)

 トランザクション展性攻撃耐性に関して書く前に、そもそもトランザクション展性攻撃って何だ、どういった手法で攻撃するんだ、という話をしておかなくてはいけないと思う。


 ビットコインはtx_outに書かれているロックスクリプトを解錠するための署名を行うとき、自分が新たに作成するtxの署名スクリプト以外の要素にロックスクリプトを加えたものををシリアライズしてそれに署名を行う。


 つまり、署名によって守られるのは参照しているロックスクリプトと、署名用スクリプト"以外の"トランザクションの要素となる。署名用スクリプトが本当に署名者が作成したものかどうかを判定する仕組みは無いのだ。
 そして署名用スクリプトを含む新たに生成されたトランザクションは署名検証が通りさえすればそれが正式なものとしてブロックに格納される。


 この仕組みを悪用して他人が生成したトランザクションのIDを変えてしまうのがトランザクション展性攻撃と呼ばれる攻撃だ。


 トランザクション展性それそのものの意味はもっと広義の意味があるので、たまたまHash値が衝突してしまうものもトランザクション展性であり、そちらを使った攻撃もできなくはないが、ここでは無視する。



トランザクション展性攻撃(攻撃方法)

 ここでは実際に使われた攻撃方法を紹介する。おそらくこれが一般的で(攻撃を一般的と言って良いのか分からないが)簡単で確実な攻撃方法だ。


 この攻撃で攻撃者は下記の手順で「tx_idは違うが署名検証は正常に通過する攻撃用コピートランザクション」を作成して攻撃する。

  1. 攻撃対象者がブロードキャストした、まだブロックに格納されていないトランザクションを取得する。
  2. 署名スクリプト以外に触れると、署名が通らなくなるので、署名スクリプトを書き換える。この時、元の署名スクリプトと「書き方は異なるが同じ意味を持つスクリプト」に書き換える。
  3. 攻撃用コピートランザクションをネットワークに投げる
  4. マイナーが攻撃者が生成した攻撃用コピートランザクションをブロックに入れれば攻撃は成功。元のトランザクションは棄却されるのでブロックに入ることはない。

 この攻撃をすることで、攻撃対象者が本来意図していない形にトランザクションが形を変え、ブロックに格納されてしまうことになる。


トランザクション展性攻撃(被害)

 さて、攻撃方法は分かったがこの攻撃、攻撃された側はなにか困るのか?という疑問がある。送金先が変えられたわけでも送金料が変えられたわけでもない。ただ、トランザクションIDが変わっただけだ。


 実際、単にこの攻撃をするのは現状としてほぼ無意味である。しかし、ある条件下ではこの攻撃が脅威になり得る。それは例えば以下の通り。

  1. 送金の確認を自分が生成したトランザクションIDだけを追って確認していた場合
  2. ブロックに格納される前のトランザクションを参照して新たにトランザクションを生成したい場合

 1について、これが実際の被害となって現れたのがあの「Mt.GOX事件」だ。マウントゴックスは取引所からの送金をトランザクションIDを追って確認していただけで、きちんと送金のたびにシステムをビットコインネットワークと同期させて、実際に手元にあるお金がどうなっているのか、逐一照合して確認を取っていなかったのだ。


 2について説明する前にまず、トランザクションのtx_inの中身を思い出していただきたいのだが、tx_inにはout_pointと呼ばれる参照先のトランザクションIDとその中で自分が参照したいtx_outをインデックス番号で示すフィールドがある。
 
 では、ブロックに格納される前のトランザクションを使用しようとして、新たにトランザクションをネットワークに投げたとする、何も起こらなければ先に投げたトランザクションが承認された後、そのトランザクションを参照しているトランザクションが続いて承認される。
 しかしここで、参照先のトランザクションが展性攻撃を受けると、新たに生成したトランザクションは参照先を失ってそれそのものが無効なトランザクションとなってしまうのだ。


 トランザクション展性の被害は上記以外にもパターンはあると思うが、要するにトランザクションIDが作成者の意図しないIDに変えられてしまうことが原因で発生する問題が起こりえるという話だ。



Segwitとトランザクション展性攻撃耐性

 以上を踏まえて、やっと本題。だが、実はもう前回の記事でここの部分はほとんど書いてある。Segwitは署名スクリプトをwitnessとして分離する。このwitnessはトランザクションIDを計算するときに使用されないので、witnessに変更が加えられたとしても、トランザクションIDは変えられない。そのため、上記で書いたような「署名スクリプトを別の言葉で同じ意味になるように書き換える」という攻撃方法が出来なくなる。


 上記以外にもトランザクション展性攻撃は可能だが、少なくとも(後述するP2WPKHやP2WSHを素直に使った場合は)上記の攻撃への耐性はついたことになる。


 また、開発者にとってトランザクションIDだけを追えば良いというのは仕事の助けになる。なぜなら送金のを確認する度にノードをブロックチェーンと同期させてトランザクション展性攻撃を受けていないか確認しなくても良くなるからだ。



〜4へ続く〜


私感など(関係ないことも含む)

 Witnessプログラムについては後で書くけども、少なくともバージョン0のWitnessプログラムでは「Witness部分を同じ意味になるように書き換える」ということが出来ないっぽい(制限が大きいので)。大きい構造的に、というのと、細かい仕組みの中(バージョン0内)との二重でブロックが効いて署名の書き換えはできなくなりそう。というか、きっと出来ないんだろう。
 これも後から書く事になると思うけど(忘れていなければ)、Witnessプログラムって新たなバージョンを追加した時に後方互換しやすいように前もって対策が打ってある。なので、署名に関する変更であればSegwit採用以降はソフトフォークで結構何でも追加できるようになると思う。
(これは、量子耐性を持った暗号を新たに採用するときなどに都合が良いと言われている)


Segwitに関して調べた記録1

MonacoinでSegwit可決されたということで、今更だがSegwitに関して詳しく調べてみた。折角なので他人が見れる形で調べた内容に関する記録を残しておこうと思う。


はじめに(事前知識など)

 これから私が書くのはSegwitがもたらしてくれる利益や不利益などと言った概要的な内容ではなく、詳細な仕組みに関することがメインだ。
 そのため、現時点で「Segwitって何?」という方には全く理解できないであろう内容をこれから書いていく。また、ビットコインのトランザクションの構造やスクリプトのシステムをおおまかにでも理解できていないなら、これから私が書くことを読んでも理解できないかもしれない。



見出し

 都合により変更する可能性が大きいが、ざっくりと以下のような感じで書いていこうと思う。

  1. 概要(これだけ今回書く)
  2. トランザクションと新たに追加されるWitnessという構造に関して
  3. Segwitとトランザクション展性攻撃耐性に関して
  4. Witnessと署名検証に関して
  5. Witnessとアドレスフォーマットに関して


1,Segwitの概要

 SegwitはBIP141〜145に詳細な仕組みが記載されている。大まかな理解として良く知られているのは「トランザクションから署名部分を分離する」ということかと思う。トランザクションから署名部分を分離すると何が嬉しいのか、一般的に以下のように言われている。

  1. ブロックサイズを変更することなく(ハードフォークすることなく)実質的に時間あたりのトランザクションの処理数を増やすことができる
  2. トランザクション展性攻撃に対する耐性が増す

 1の部分は感覚でも理解できると思う。署名部分をWitnessと呼ばれる新しい構造体としてトランザクションとは別に保管することで、トランザクションの署名部分はトランザクションサイズとしてカウントされなくなるので、トランザクションサイズは小さくなったとみなされる。
 トランザクションのサイズが小さくなれば、ブロックサイズが今までと同じでも、より多くのトランザクションをブロックの中に詰めることができるようになる。

 2の部分は説明がいると思う(少なくとも私には説明が必要だった)。が、これを説明するにはトランザクション展性を用いた攻撃に関することも併せて書かないといけなくなるので、次以降に回す。


~2へ続く~


私感など雑記(以降関係のない話)

 Segwitに限らず、暗号通貨に関して日本語ソースって本当に無い。技術的なことに関するものは英語ソースでも少ないように思う。困るよね。