Develop with pleasure!

福岡でCloudとかBlockchainとか。

2P-ECDSA: Fungible 2-of-2 MultiSigs for Today's Bitcoin at Scaling Bitcoin 2018

Scaling Bitcoin 2018 復習シリーズ。今回はLightning LabsのConner Fromknechtによる「2P-ECDSA: Fungible 2-of-2 MultiSigs for Today's Bitcoin」の発表↓

youtu.be

書き起こしは↓ scriptless-ecdsa

前半はLindellベースの2者間のECDSA署名プロトコル↓の解説と、後半はそれを実際にLightning Networkに適用する際の考慮事項についてまとめた発表になってる。

techmedia-think.hatenablog.com

あとところどころPedroの話が引用されてるけど、それはこのセッションの前に発表されたMulti-Hop Locksの話↓

techmedia-think.hatenablog.com

2P-ECDSAの歴史

  • 2016年にBlockstreamのAndrew PoelstraがSchnorrベースのScriptless Scriptを発表
    これにより共有データ(通常ペイメントハッシュ)をブロックチェーン上で明らかにすることなく、クロスチェーンでコインのスワップすることが可能になった。チェーン間でトランザクションがリンクされることもない。彼はその後、LNのハッシュプリイメージのチャレンジをこれで置き換える公正を提案する。
  • 2017年3月、PedroがMulti-Hop Locksの発表で言及したように、LNの各ホップで支払い情報がランダム化されることを保証するようになった。全ての決済は伝播された順に決済される。
    • これによりプライバシーが向上
    • Pedroの言うようなWormhole Attackへの防御になる
  • 2017年末、Yehuda Lindellは、効率的な2p-ECDSA署名プロトコルを発表した。このプロトコルは現在のBitcoinのノードと完全な下位互換があり、どのノードもこの署名検証を行える。また現在存在するP2PKHやP2WPKHで利用可能。
  • 2018年4月、PedroがLNのホップの無相関化のフレームワークを形式化したMulti Hop Locksをリリースした。これには2p-ECDSAに基づく、Scriptless Scriptの構築が含まれている。また経路内の各ホップはECDSAをベースにしてもいいし、Schnorrをベースにしてもいい。つまり経路内にECDSAとSchnorrが混在していても問題ない。そのため、現在のLNにECDSAベースのMulti Hop Locksを導入した後、後でSchnorrがBitcoinに導入されたら、LNのネットワークを断片化することなくスムーズに移行することができる。
  • 現在、いくつかの2p-ECDSAを研究している。

2p-ECDSAの概要

  • アリスは秘密鍵aと対応する公開鍵A = aGを持っている。
  • ボブは秘密鍵bと対応する公開鍵B = bGを持っている。
  • お互い公開鍵は共有しており、公開鍵Q = (ab)G = aB = bAを計算する。Qの対応する秘密鍵ab
    • 二人ともabのデータは知らない。 *二人で協力してQに対して有効なECDSA署名を生成する。

有効なECDSA署名を生成するにあたって、2つのアルゴリズムが必要になる。

  • KeyGen(オフライン)
    オンラインのSignプロトコルに参加するためのアリスとボブのセットアップ。コスト的に高価だが実行するのは1回だけ。
  • Sign(オンライン)
    効率的だが2回の往復が発生するオンライン署名プロトコルで、Qに対して有効なECDSA署名を生成する。

KeyGen

  1. 基本的にアリスとボブはそれぞれが持つ公開鍵と、その公開鍵の離散対数(秘密鍵)を知っていることの証明を交換する。これは標準的なShcnorr署名のデータを確認することで、その公開鍵に対応する秘密鍵を持っていることを確認できる。
  2. アリスはPaillier暗号用の鍵ペア(PSK, PPK)を生成する。またアリスがボブを騙すことが無いよう、鍵PPKが {N= p_1 * p_2} {p_1} {p_2}で構成されていることを証明するゼロ知識証明を提供する。
  3. アリスは公開鍵PPKで秘密鍵を暗号化し、暗号テキスト {c = Enc_{PPK}(a)}を作成する。
  4. アリスは(PPK, c)をボブに送る。
    • ボブは暗号テキストを受け取るだけで、元の値のサイズを知ることができないため、アリスはそれが小さいことを証明する必要がある。この証明のため、一緒に暗号テキストcの値が { 0 < Dec_{PSK}(c) < q}の範囲内であることをゼロ知識証明を提供する(qは曲線secp256k1の位数)。実際、暗号テキストは元の値よりはるかに大きなデータになる。
    • そしてcにアリスの秘密鍵を含まれていること =  {A = Dec_{PSK}(c) G} を証明する。
    • Lindellはこれを証明するのに新しいゼロ知識証明を発明しなければならず、2つの異なる暗号システムを混在させていた。
  5. ボブは、受信した証明全てを検証し、Q = bAを計算する。
  6. アリスはQ = aBを計算する。

KeyGenの結果、

  • アリスは2p-ECDSAの公開鍵Q = abG秘密鍵(a, PSK)を持つ。
  • ボブは2p-ECDSAの公開鍵Q = abG秘密鍵(b, c, PPK)を持つ。

Sgin

Paillier暗号の特性

なぜ、KeyGenでPaillierを使っているのか?というと、主な理由は、ECDSAではScnorrのように公開鍵や署名の加算ができない(公開鍵や署名が線形性を持っていないため)。このため非対話型の集約に適していない。ただ、Palliler暗号データは以下のような部分的な準同型の性質を持っている。

  • 加法準同型性(暗号化したデータ同士を加算できる)
    D(E(m1) * E(m2) mod N2) = m1 + m2 mod N
  • 暗号化したデータの元のメッセージに対してスカラ倍できるスカラ乗算
    D(E(m1)k mod N2) = k*m mod N

ボブはこれらをPPKを使って秘密鍵(PSK)の知識無しに計算することができる。

署名プロトコル

ECDSAの署名データは(r, s)。sは、 {\displaystyle s = \frac{H(m) + r * x}{k}}で、rはR = kGのx座標。

このECDSAの署名をアリスとボブは以下のステップで計算する。

  1. アリスとボブはそれぞれnonceを選択し、この公開鍵とそのnonceを持っていることのゼロ知識証明を共有する。アリス: {K_a = k_aG}、ボブ: {K_b = k_bG}
  2. ボブは暗号データ {\displaystyle c_1 = Enc_{PPK}(\frac{H(m)}{k_b})} {v = \frac{r * b}{k_b}}を計算する。ここでrは {R = k_a * k_b G}のx座標。
  3. ボブは {\displaystyle c' = c_1 * c^{v} \mod N^{2} = Enc_{PPK}(\frac{H(m) + r * a * b}{k_b})}を計算し、アリスに送る。
  4. アリスはそれを復号化した {s' = Dec_{PSK}(c')}を計算し、 {s'' = \frac{s'}{k_a} \mod q}
  5. 計算結果のs''は {\displaystyle s'' = \frac{H(m) + r * a * b}{k_a * k_b}}となる。
  6. 最後にアリスは {s = min(s'', q - s'' \mod q)}をセットし、(r, s)をSignアルゴリズムのアウトプットとする。

通常のECDSAプロトコルと比較すると、nonce kがアリスとボブのkに、秘密鍵もアリスとボブの秘密鍵に置き換わっている。

こうやって生成した署名はECDSA署名として機能する。最後のステップはLOW_Sルールの適用。

Scriptless Scriptの署名も同様のアプローチだが、シークレットの抽出で余分なラウンドを必要とする。詳細はPedroのペーパー参照。

ベンチマーク

  時間 割り当てられたメモリ 割り当て数 メッセージ数
KeyGen 1.07 秒 4.99 MB 13.31 K 7
Sign 28.66 ミリ秒 97 KB 746 4
Scriptless-Sign 29.40 ミリ秒 118 KB 1.12 K 5+1

KeyGenプロトコルの実際の暗号や複雑さを考慮するともっと遅くなると思われたが全体的に1.07秒で意外と速い結果になっている。おそらく1番遅い部分はgolangのbigintライブラリを使用している箇所で、これは時間が固定時間でなくメモリパフォーマンスに問題があることで有名だ。そのため、この時間は2倍 or 5倍 or 10倍に速くなる可能性がある。

署名は見ての通り30ミリ秒未満。結構大きい。オンラインプロトコルとしては上手く動作する。

Scriptless-Signには多くの最適化作業が残っている。

ベンチマークのコードは↓

github.com

LNへのデプロイの考慮事項

2P-ECDSA/Schnorrのデプロイの場合

Fundingアウトプット

現在は2-of-2のマルチシグにコインをロックしている部分。このコインをアンロックするには、協調してクローズする場合とCommitment Txをブロードキャストする場合の2ケースがあるが、いずれも2人の署名を必要とする。この部分をP2WPKHのロックスクリプトに置き換える。

通常の2-of-2のマルチシグ、Schnorr版、2P-ECDSA版、P2WPKHにおけるWitness Scriptとアンロックに必要なwitnessは以下のようになる。

  witness witness script
通常 OP_0 <aGの署名> <bGの署名> OP_2 <aGの公開鍵> <bGの公開鍵> OP_2 OP_CHECKMULTISIG
Schnorr <(a+b)Gの署名> <(a+b)Gの公開鍵> OP_CHECKSCHNORRSIG
2P-ECDSA <abGの署名> <abGの公開鍵> OP_CHECKSIG
P2WKH <aGの署名> <aGの公開鍵> OP_CHECKSIG

使用するスペースは約半分になる。2つの公開鍵は1つに、2つの署名は1つの署名になる。また、非広告チャネルのプライバシーを守るチャンスにもなる。LNのノードでチャネルを広告している場合は、プライバシーを諦めることになるが、プライベートチャネルの場合、Funding Txは通常のP2PKHもしくはP2WPKHのように見えるため、プライバシー上の大きなアドバンテージになる。特に、多くのモバイルデバイスやラップトップ上のノードが、ルーティングのためにノードを広告しないネットワークに移行するにつれて、大きな意味を持つ。また最後に、ゴシップレイヤーの帯域幅が少なくなる。署名が1つ少ないので一般的にネットワークの負荷状況が改善する。

HTLCアウトプット

非標準のHTLCスクリプトで(標準というのはBIP-199のこと?)、2-of-2のマルチシグを使っている。HTLCスクリプトには、offeredとreceivedの2種類のスクリプトがある。2つはほとんど似ているが、チャネル上のどの方向を向いているかが異なり、両方とも2-of-2のマルチシグを必要とする。スクリプト内のoffered-timeoutおよびreceived-successの条件でコインを使用する際に2-of-2のマルチシグを必要とし、その部分をよりシンプルになるよう置き換える。

例えば現在のReceived HTLCスクリプト

# revocation clause
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocation pubkey))> OP_EQUAL
OP_IF
  OP_CHECKSIG
OP_ELSE
  <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
  OP_IF
    # success clause
    OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY 2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
  OP_ELSE
    # timeout clause
    OP_DROP <cltv_expire> OP_CLTV OP_DROP OP_CHECKSIG
  OP_ENDIF
OP_ENDIF

のようなスクリプトになっているが、2P-ECDSAを利用してより簡単なHTLCスクリプトにすることができる↓

OP_IF
  # revocation clause
  revocationpubkey
OP_ELSE
  OP_IF
    # timeout clause
    <cltv_expire> OP_CLTV OP_DROP <remote_delay_pubkey>
  OP_ELSE
    # success clause
    <2p_htlc_pubkey>
  OP_ENDIF
OP_ENDIF
OP_CHECKSIG

これにより、

  • スクリプトのサイズ自体が20%削減
  • スクリプトの可読性が向上
  • witnessのサイズ削減
    • successの場合のwitnessサイズは78%削減される。
    • revocationのケースでは30%ほど小さくなる。
    • タイムアウトの場合のwitnessサイズは同じまま。

Offered-HTLCスクリプトでも同様の改善が期待できる。

Scriptlessな2P-ECDSA/Schnorrのデプロイの場合

  • HTLCアウトプット
    Scriptlessな2P-ECDSA/Schnorrを使用すると、HTLCのスクリプトからペイメントハッシュを削除することができる。また拡張によってwitnessからプリイメージを削除できるので、witnessから52バイト削減できる。

スペースの削減という観点からは、手数料も安くなり、ブロックチェーンの負荷も軽減する。

双方向の2P-ECDSA

LNのチャネルは双方向なので、HTLCを更新したい場合、全ての更新とパラメータ(ペイメントハッシュや、タイムロック時間など)をチャネルの反対側に送信し、各チャネルはその更新を適用し、その後作成した署名のバッチを送信する。これを行うと片方の参加者のみが署名で終わる。

オンチェーン上に1つのFunding Outputがロックされていて、どちらの参加者もこれを使用するための署名を開始できる。どちらからでも更新を開始できるように、同じ鍵ペアの2つのインスタンスをセットアップし、それでFunding Output(もしくは同様のもの)のコインを使用するCommitment Txに署名できるようにする。

※ この部分の説明がイマイチよく分かってない。

オニオンパケット

BOLT 04で定義されている現在のonionパケットのデータ構造は以下のようになっている

サイズ 名称
1 version
33 public_key
20*65 hops_data
32 hmac

この内、hops_dataはメッセージ転送中に関連するホップによって使われる情報を含む20個の固定サイズのパケットで構成される。

hops_dataを構成する1つ1つのパケットのデータ構造は以下のようなもの↓

サイズ 名称
1 realm
32 per-hop
32 MAC
filter

このうち2P-ECDSA/Schnorrのデプロイにあたって変更するのはホップ毎のペイロードのデータ(per-hop)。

現在のper-hopペイロードは以下の32バイト

サイズ 名称
8 short_channel_id
8 amt_to_forward
4 outgoing_cltv_value
12 padding

新しいペイロードは以下のような構成になる。サイズは161バイトで、トータルのパケットサイズは3880バイトとなり元の1300バイトから約3倍のデータ増になる。

サイズ 名称
8 short_channel_id
8 amt_to_forward
4 outgoing_cltv_value
33 incoming_lock_pubkey
64 incoming_lock_dlog_pok
32 hop_lock_secret
12 padding

これらを構築して解読する際のボトルネックの大半は、一時鍵導出やBlindng Factorなどの非対称暗号操作で、ホップ数の増加と共に線形スケールする。そのため、パケットサイズの増加は構築/解読にほとんど影響を及ぼさない可能性がある。

2P-ECDSAとScriptless Scriptのサマリ

メリット

  • 現時点でデプロイ可能
  • スクリプトとwitnessが小さくなり、手数料が安くなる。
  • funding outputの匿名セットの向上によりオンチェーンプライバシーが向上
  • ホップ間の相関を無くすことでオフチェーンプライバシーが向上
    2P-ECDSAは、既存のトラフィックに混在し、Schnorrが始まると初期は匿名セットが小さくなる。ただ時間の経過と共にSchnorrに移行すると思われる。
  • リアルなProof-of-Payment(Invoice Tunneling)
  • この分野で多くの研究されている。

デメリット

  • 複雑である
    • 正しく実装する決して簡単ではない。
    • モバイルデバイスのリソース使用量はそれほど大きくないけど、プルーフを並行して処理するためのコアは少ない。
  • Commitment Txの更新の際により多くの情報の更新が必要で、より多くのラウンドトリップを必要とする(署名プロトコルをパイブライン化してラウンドトリップを削減することは可能かもしれない)。

The State of Atomic Swaps at Scaling Bitcoin 2018

Scaling Bitcoin 2018復習シリーズ。今回は10/7のThomas EizingerCOMITプロトコル開発してる人みたい)が発表した「The State of Atomic Swaps」の内容について見てみる↓

www.youtube.com

書き起こしは↓

http://diyhpl.us/wiki/transcripts/scalingbitcoin/tokyo-2018/atomic-swaps/

Atomic Swap

Atomic Swapはチェーン間で相手を信用することなく、アトミックにコインを交換するのに使用されるプロトコル。一般的なプロトコルとしてはHTLCが利用される。

アリスがBitcoinを持ち、ボブがLitecoinを持っている状態でアリスとボブはそれぞれBitcoinとLitecoinを交換したい場合、以下のような手順で相手を信用することなく各チェーンのコインをアトミックに交換できる。

  1. アリスはシークレットAをランダムに選択し、そのハッシュ値H(A)をボブに伝える。
  2. アリスは自分のBitcoinを以下のいずれかの条件でアンロック可能なスクリプト宛に送金するトランザクションを作成しBitcoinネットワークにブロードキャストする。
    • H(A)のプリイメージを提供すればボブの鍵でアンロック可能。
    • 2日後アリスの鍵でアンロック可能
  3. ボブは自分のLitecoinを以下のいずれかの条件でアンロック可能なスクリプト宛に送金するトランザクションを作成しLitecoinネットワークにブロードキャストする。
    • H(A)のプリイメージを提供すればアリスの鍵でアンロック可能。
    • 1日後ボブの鍵でアンロック可能
  4. アリスはシークレットAを使って3のボブのLitecoinを入手するトランザクションを作成しLitecoinネットワークにブロードキャストする。
  5. ボブはLitecoinのブロックチェーン上で4のトランザクションを確認することでシークレットAの値がわかる。
  6. ボブはシークレットAの値を使って2のアリスのBitcoinを入手するトランザクションを作成しBitcoinネットワークにブロードキャストする。

f:id:techmedia-think:20181018203139p:plain

このようにシークレットとそのハッシュ値、タイムロックの仕組みを使って相手を信用することなくコインを交換するHTLCプロトコルが構成できる。

これを上記のようなBitcoin Scriptを使うことなく、署名技術を使って実現するScriptless Scriptというアプローチもある。

HTLCを使ったスワップの不公平

上記のようなHTLCを使ったAtomic Swapには1点、不公平な部分がある。

シークレットを生成した側のアリスには、シークレットを公開しない=HTLCをセットアップしたけど交換はしないというアドバンテージがある。この場合、タイムロックの期間が過ぎるとコインは自分の元に戻ってくる。コインの交換レートに合意して、両方のチェーン上でHTLCにコインをロックした後に、市場の取引レートが劇的に変わると、アリスはセットアップ時のレートで取引したくなくなり、HTLCを実行することなくタイムロックを待ち払い戻しを選択する可能性がある。この場合、取引相手のボブも払い戻し用のトランザクションを発行する。ボブにとっては、最初に合意したレートでのコインの交換ができず、セットアップと払い出し用の2つのトランザクションの手数料を負担しただけになる。

Atomic Swapプロトコルの修正

↑の不公平な状態を解消するため、Atomic Swapプロトコルにペナルティを導入する。重要なのは正しく罰することで、上記のケースではシークレットを公開しなかったアリスを罰することになる。アリスが正しい行動をしなかった場合=シークレットを公開しなかった場合に、アリスから担保を奪うようにする。

公正なAtomic Swap リビジョン1

リビジョン1で導入するのは、2つめのHTLCもしくは条件付き支払いを追加する。これはアリスがBitcoin上でボブに支払う代わりに、Litecoinのチェーン上に資金を償還した際に戻ってくる担保を作る。

担保設計

f:id:techmedia-think:20181018203612p:plain

担保は条件付き支払いで、支払いパスが逆なだけで、他のHTLCで使われているのと同じプリイメージとハッシュを使用する。シークレットが明らかになった場合、その資金はアリスが手にし、タイムアウト後はボブが資金を入手できる。アリスがタイムロックを経過するまだ待っていたら、この担保はボブに渡る。これによりアリスがボブにプリイメージを明らかにするインセンティブができる。

ただ今度はアリスからボブへのトラストが発生する。アリスが2つめの担保用のHTLCトランザクションブロックチェーンにブロードキャスト後、ボブがHTLCトランザクションを発行せずアリスの担保用のHTLCのタイムアウトまで待つと、ボブは何もせずにアリスの担保分のコインを入手できてしまう。そのためこれは理想的なプロトコルではない。

公正なAtomic Swap リビジョン2

上記問題を解消するには、ボブがAtomic Swapの条件にコミットしていない状態にある時、アリスの担保は正しくアリスに戻ってくるようにする必要がある。そのためにアリスの担保とボブのHTLCの2つを以下のように1トランザクションで構成する。

f:id:techmedia-think:20181018204154p:plain

  1. アリスはBitcoinをボブに支払うHTLCトランザクションを作成しブロードキャストする。
  2. アリスは自身の担保を入れたLitecoin用の担保トランザクションを構成する。アリスの担保をインプットとし、アウトプットの量は「ボブがアリスに支払うLitecoinの量」+ 「アリスの担保分のLitecoin」。
  3. 2で作成した担保トランザクションにアリスの署名を付与し、ボブに渡す。
  4. ボブは受け取った担保トランザクションのインプットに自分の資金をセットし、署名を付与しブロードキャストする。

f:id:techmedia-think:20181019101856p:plain
2,3で作成するトランザクションのインプット/アウトプット。ボブがインプットやお釣り用のアウトプットを追加できるようするため、アリスが作成する署名はSIGHASH_SINGLEを使って署名されると思われる。

トランザクションがLitecoinのネットワークにブロードキャストされると、アリスは担保があるためそれを手に入れるインセンティブが発生する。アリスがLitecoinを入手すると、ボブはBitcoinを入手するのに必要なシークレットが手に入る。

アリスがシークレットを明らかにせず、タイムアウト期間を過ぎると、HTLCの条件からボブは自分のLitecoinとアリスの担保分Litecoinを手にする。

3の後に4でボブがトランザクションをブロードキャストする前までであれば、アリスは担保トランザクションのインプットにセットしたUTXOを別のトランザクションで使用すればキャンセルが可能。なので3の後にボブから応答がない場合はアリスはAtomic Swapをキャンセルして担保金を取り戻せる。

プライバシー

上記のような公平なAtomic Swapプロトコルが考案したのでプライバシーについて考える。Atomic Swapをプライベートにする方法としてはScriptless Scriptを利用する方法がある。Scriptless Scriptはシークレットとハッシュ値を署名技術にエンコードできるのでチェーン上で他のトランザクションと区別がつかなくなる。

セットアップ

f:id:techmedia-think:20181019105207p:plain

アリスとボブはそれぞれ鍵ペア(アリス:xa、ボブ:xb)を持ち、アリスだけ別にシークレット tを用意する。アリスはボブの秘密鍵とtを含むアドレスを計算する。このアドレスはボブの公開鍵とtGを加算した楕円曲線上の点をアドレスとしてエンコードすることで計算できる。ボブは資金を償還するのに2人の秘密鍵を必要とするマルチシグにLitecoinをロックする。この段階でアリスはボブの秘密鍵を知らないので、アリスがロックされた資金をアンロックできない。ボブはボブでシークレットtを知らないのでボブも資金をアンロックできない。ということでアリスもボブもこの段階ではどちらも資金をアンロックできない。

コインのアンロック

  1. ボブはLitecoin側のマルチシグにロックされているコインをアンロックするのに必要なAdaptor Signatureを作成する。これはコインをアンロックするのに必要な署名の一部で、これを完全な署名にするには、アリスが署名にtの値を含めるようにしないといけないよう設計されてる。
  2. アリスはボブの部分署名を完成させ、litecoinを入手するために必要な完全な署名を得る。これによりアリスのtは明らかになる。そしてボブがtを知り、tを自分の秘密鍵に加算してBitcoinをアンロックする署名を作成することができる。

Adaptor Signature使った署名のエンコード方法の詳細は触れられていないが、初期にAndrew Poelstraが発表したプロトコルは両方のチェーンでマルチシグにコインをロックするタイプだったので↓、そのアプローチとは異なるアプローチになってる。確かにtが分かればアンロック可能であれば、片側のロック条件はマルチシグじゃなくて良い。

techmedia-think.hatenablog.com

重要なのはこの仕組みがHTLCと同じ特性を持っているということ。アリスは最初に彼女だけが知っているシークレットを持ち、その値を明らかにすることなくボブの資金を手にすることはできない。また開始前にお互いにnLocktime付きのトランザクションに署名しておくことで、両者は資金を取り戻すことができる。

公正なAtomic Swapという意味でや↑のトランザクションは担保が無い。その点については特に言及されてないけど、担保を付与する場合は、おそらくLitecoin側のトランザクションにはアリスの担保分のインプットが追加され、マルチシグにロックされる。そしてnLocktime付きのトランザクションタイムアウト後、その取り分がボブに全部いくよう設計しておくようなパターンになると思われる。

Output Descriptorとscantxoutsetを使ってUTXOセットをスキャンする

Bitcoin Core 0.17.0からUTXOセットをスキャンするscantxoutsetというRPCが追加された。

Bitcoin Core :: scantxoutset (0.17.0 RPC)

今まではウォレット内に鍵を持つUTXOの情報はlistunspentなどで取ってこれてたけど、↑はウォレット機能とは別で、UTXOセットの中から指定した条件に合うUTXOを検索することができる。

この時、検索対象を指定する際に使用する記述子がOutput Descriptor↓

bitcoin/descriptors.md at 0.17 · bitcoin/bitcoin · GitHub

(訳は後述)

Output Descriptorを指定してscantxoutsetでUTXOを検索

scantxoutsetは以下のように2つの引数を取る。

$ bitcoin-cli scantxoutset <action> <scanobjects>
  • action
    実行するアクションを指定。
    • startでスキャンを開始
    • abortで現在のスキャンを打ち切り
    • statusで現在のスキャンの進捗を確認
  • scanobjects
    スキャン対象を配列で指定。各要素で指定可能なスキャン対象は今のところ以下の3つ
    • descriptor: 後述のOutput Descriptorの文字列を指定
    • ['desc': xxx, 'range': n]: (オプション)Output Descriptorとメタデータを含むオブジェクト。子HDチェーンをどこまで探索するかのインデックスを指定して検索したい場合(デフォルト:1000)

例えば、公開鍵0259f6658325c4e3ca6fb38f657ffcbf4b1c45ef4f0c1dd86d5f6c0cebb0e09520のP2PKHのUTXOを探す場合、以下のようにscantxoutsetを実行してしばらく待つと結果が得られる↓

$ bitcoin-cli -testnet scantxoutset start "[  \"pkh(0259f6658325c4e3ca6fb38f657ffcbf4b1c45ef4f0c1dd86d5f6c0cebb0e09520)\" ]" 
{
  "success": true,
  "searched_items": 20353944,
  "unspents": [
    {
      "txid": "1915bdd359feb0bb12bc4f6f1f0791b982def6936af420473f892bacd16db014",
      "vout": 1,
      "scriptPubKey": "76a9143b9722f91a2e50d913dadc3a6a8a88a58a7b859788ac",
      "amount": 0.10015556,
      "height": 1117751
    },
    {
      "txid": "e9dcfee7eb0715570cf8b3cc2149309ca4c0af3a4387f4eb92a4c04d746986ed",
      "vout": 1,
      "scriptPubKey": "76a9143b9722f91a2e50d913dadc3a6a8a88a58a7b859788ac",
      "amount": 0.46970645,
      "height": 1117751
    }
  ],
  "total_amount": 0.56986201
}

実行中は別のターミナルから↓を実行するとスキャンの進捗(%)が確認可能。

$ bitcoin-cli -testnet scantxoutset status
{
  "progress": 45
}

とこんな感じで、手軽にUTXOセットを検索できるようになったのは便利だ。

scanobjectsの指定方法は以下のようにOutput Descriptorを構成することで様々な検索が可能。

Output Descriptorの機能

以下、Output Descriptorの機能部分の訳↓

現在以下のOutput Descriptorをサポートしている。

  • pk関数を介して、Pay-to-pubkeyスクリプト(P2PK)をサポート
  • pkh関数を介して、Pay-to-pubkey-hashスクリプト(P2PKH)をサポート
  • wpkh関数を介して、Pay-to-witness-pubkey-hashスクリプト(P2WPK)をサポート
  • sh関数を介して、Pay-to-script-hashスクリプト(P2SH)をサポート
  • wsh関数を介して、Pay-to-witness-script-hashスクリプト(P2WSH)をサポート
  • multi関数を介して、マルチシグスクリプトをサポート
  • addr関数を介して、サポートされる任意のアドレスタイプ
  • raw関数を介して、RAWスクリプトのhex表記をサポート
  • hex表記の公開鍵(圧縮、非圧縮)または、BIP32拡張公開鍵と導出パス

サンプル

  • pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)は、P2PKアウトプットを表す。
  • pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)は、P2PKHアウトプットを表す。
  • wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)は、P2WPKHアウトプットを表す。
  • sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))は、P2SH-P2WPKHアウトプットを表す。
  • combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)は、P2PK、P2PKH、P2WPKH、P2SH-P2WPKHアウトプットを表す。
  • sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))は、P2SH-P2WSH-P2PKHアウトプットを表す。
  • multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)は、素の1-of-2のマルチシグを表す。
  • sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))は、P2SHの2-of-2のマルチシグを表す。
  • wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))はP2WSHの2-of-3のマルチシグを表す。
  • sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)))はP2SH-P2WSHの1-of-3のマルチシグを表す
  • pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8)は、指定されたxpubの公開鍵部分を使った単一のP2PKアウトプットを示す。
  • pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)は、指定されたxpubの1'/2の子鍵を使った単一のP2PKHアウトプットを示す。
  • wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/0/*))は、2つのHDチェーンの対応する導出パスの公開鍵を使った1-of-2のP2WSHマルチシグアウトプットを示す。

参照

記述子はいくつかのタイプの式で構成される。トップレベルの式は常にSCRIPT

SCRIPT式:

  • sh(SCRIPT)(トップレベルのみ): 引数を埋め込んだP2SH
  • wsh(SCRIPT)(別のwshの内部であってはならない): 引数を埋め込んだP2WSH
  • pk(KEY)(どこでも可): 与えられた公開鍵P2PKアウトプット
  • pkh(KEY)(どこでも可): 与えられた公開鍵のP2PKHアウトプット(公開鍵ハッシュしか知らない場合は代わりにaddrを使用)
  • wpkh(KEY)wshの内部以外): 与えられた圧縮公開鍵のP2WPKHアウトプット
  • combo(KEY)(トップレベルのみ): pk(KEY)pkh(KEY)のコレクションのエイリアス。もしkeyが圧縮されている場合、wpkh(KEY)sh(wpkh(KEY))も含まれる。
  • multi(k,KEY_1,KEY_2,...,KEY_n)(どこでも可): k-of-nのマルチシグスクリプト
  • addr(ADDR)(トップレベルのみ): ADDRが展開されるスクリプト
  • raw(HEX)(トップレベルのみ): HEXとして16進エンコードされたスクリプト

KEY式:

  • Hexエンコードされた公開鍵(02および03で始まる場合は66文字、04で始まる場合は130文字)。
    • wpkhwshの内部では、圧縮された公開鍵のみが許可される。
  • WIFエンコードされた秘密鍵は、対応する公開鍵の代わりに同じ意味で指定できる。(BIP 32で定義されている)xpubエンコードされた拡張公開鍵もしくは、xprvエンコードされた拡張秘密鍵
    • 0以上の/NUMの非強化鍵もしくは/NUM'強化鍵のBIP 32導出パスが続く。
    • オプションで、/*もしくは/*で直接的な子どもの非強化鍵、強化鍵のステップが続く。
    • 強化鍵の導出ステップの使用には、秘密鍵の提供が必要となる。
    • 'の代わりにh suffixを使って強化導出を表すことができる。

ADDR式はサポートされている任意のアドレス:

  • P2PKHアドレス(1...から始まるbase58フォーマット)。記述子内のP2PKHアドレスは、P2PKアウトプットに使用できないことに注意すること(代わりにpk関数を使うこと)。
  • P2SHアドレス(3...から始まるbase58フォーマット、BIP 13で定義)
  • Segwitアドレス(bc1...から始まるbech32フォーマット、BIP 173で定義)

説明

単一鍵のスクリプト

実際には、単一キーの構成が多く使われ、一般にP2PK、P2PKH、P2WPKHおよびP2SH-P2WPKHが含まれる。最適ではないがもっと多くの組み合わせが考えられるP2SH-P2PK, P2SH-P2PKH, P2WSH-P2PK, P2WSH-P2PKH, P2SH-P2WSH-P2PK, P2SH-P2WSH-P2PKH。

これを記述するために、これらを関数としてモデル化する。関数pk (P2PK)、pkh (P2PKH)、wpkh (P2WPKH)は、16進表記の公開鍵を入力として受け取り、対応するscriptPubKeyを返す。関数sh (P2SH) 、wsh (P2WSH)は入力としてスクリプトを受け取り、インプットをスクリプトとして埋め込んだP2SH及びP2WSHのアウトプットを記述したスクリプトを返す。関数名は簡潔にするためp2を省略している。

マルチシグ

いくつかのソフトウェアでは、BitcoinのOP_CHECKMULTISIG opcodeに基づいてマルチシグスクリプトを使用する。これをサポートするために、multi(k,key_1,key_2,...,key_n)関数を導入する。これは提供されたn個の公開鍵の内、任意のk個の署名が必要なk-of-nのマルチシグを表す。

BIP 32導出鍵とチェーン

最新のウォレットソフトウェアやハードウェアはBIP 32(HDキー)を利用して導出した鍵を使用する。期待される公開鍵を(一般にxpubと呼ばれる)拡張公開鍵と導出パスで構成される文字列で指定することを許可することで、これらを直接サポートする。導出パスは0以上の整数の順序で構成され、それぞれオプションで'もしくはhが付き、/文字で区切られる。文字列はオプションで、非強化導出、強化導出の全ての子鍵を参照するため/*または/*'(もしくは/*h)で終わることがある。

強化導出ステップを使って公開鍵を指定する場合、対応する秘密鍵にアクセスすることなくスクリプトを計算することはできない。

秘密鍵の包含

必要な秘密鍵を一緒にスクリプトの説明を伝えることはよく役に立つ。このため、公開鍵またはxpubがサポートされている場合、代わりにWIFフォーマットもしくはxprvを提供することができる。これは強化導出ステップや、秘密鍵の材料を含むウォレット記述子のダンプなどで秘密鍵が必要な場合に便利だ。

古いウォレットとの互換性

既存のBitcoin Coreウォレットで現在サポートされているスクリプトのセットを簡単に表現するため、入力として公開鍵を受け取り、その鍵でP2PK, P2PKH, P2WPKHおよび P2SH-P2WPHスクリプトを構成する便利な関数comboが提供される。公開鍵が圧縮されていない場合、P2PKおよびP2PKHのみを構成する。

lndで実装されているBIP-39に代わるシード管理方式「aezeed」

lndでBIP-39*1の欠点を修正するために実装されたシードの新しい管理方式「aezeed」について↓読んでみた。

https://github.com/lightningnetwork/lnd/tree/master/aezeed

2018年3月のSF Bitcoin Devsで@roasbeefがlnd v0.4-betaの紹介した際にも触れられてる。

www.youtube.com

docs.google.com

aezeedはBIP-39の以下の欠点を修正する:

  • バージョンの欠如
    バージョン情報がない場合、ウォレットがリカバリープロセス中にどのアドレスを再導出すべきか分からない場合がある(秘密鍵や公開鍵は導出できても、そこからどのアドレス:P2PKH、P2WPKH、P2SH-P2WSHを導出すべきか決定できない)。
  • ウォレットの誕生日の欠如
    ウォレットがいつできたかという情報がない場合、ウォレットが正しいユーザーのアドレスを全て確実に導出するために、チェーン内をどこまで見ていけば良いか分からない。

簡単に言うとこれらのデータをシードデータに含め、さらに暗号化したデータからmnemonicのワードリストを生成するようBIP-39を拡張した仕様になる。

具体的な仕様は↓

プレーンテキストのaezeedエンコーディング

aezeed方式のシードは、↑の欠点に対処するため以下の3つのフィールドを結合した値になる。

1バイトの内部バージョン || 2バイトのタイムスタンプ(ウォレットの誕生日) || 16バイトのエントロピー

内部バージョンは、ウォレットがウォレットの鍵を再導出する方法を知ることができるようにするためのフィールド。

2バイトのタイムスタンプはウォレットの誕生日を管理するためのフィールド。通常タイムスタンプは4バイトのデータ領域を必要とするが、このフィールドは2バイトでタイムスタンプを表現するためBitcoin Days Genesisで表される。これはBitcoinのジェネシスブロックのタイムスタンプからの日数を意味する。このフォーマットによりスペースを節約し、無駄な粒度を使わないようにすると。現在、これは2188年までの時間を表現することができる。

最後のエントロピーは、ウォレットのHDルートを導出するのに使用される。

BIP-39ではエントロピーからmnemonicを直接生成していたのに対し、aezeedではバージョンとタイムスタンプが加わった上記データからmnemonicが作られることになる。

aezeed 暗号化/復号化

BIP-39ではエントロピーにそのチェックサムを付与したデータを11bit毎に分割してmnemonicのワードリストを作成していたが、aezeedでは上記のプレーンテキストシードを暗号化してできた暗号テキスト(CipherSeed)からmnemonicのワードリストを生成する。

暗号化して生成される最終的なデータは以下の3つのフィールドを結合した値になる。

1バイトの外部バージョン || 暗号テキスト || 8バイトのチェックサム

1つめの外部バージョンは、暗号化方式を定義したもので、2つめの暗号テキストが実際にプレーンテキストシードを暗号化したデータ、最後がチェックサムで、以下のプロセスで生成される(暗号化プロセスでは、ユーザーが定義したパスフレーズが使われる。パスフレーズが指定されていない場合は、文字列「aezeed」が使われる)。

  1. 最初に、外部バージョンをバッファに追加する。外部バージョンは使用する暗号化方法について定義する。最初のバージョン(version 0)では、暗号化にscrypt(n=32768, r=8, p=1)とaezeedを使う。
  2. 次にscrypt(n=32768, r=8, p=1)を使って、暗号化に使用する強めの鍵を生成する。saltとして5バイト使って、32バイトの鍵を生成する(saltを使うのはレインボーテーブルを作成できなくするため)。
  3. 続いて暗号化プロセス。ナンスの誤用に耐性があるモダンなAEADであるaezを使用する。ここで重要な特性は、任意の入力長のブロック暗号であること。さらに設定可能なMACサイズを持っている点で、aezeed方式では64bitのチェックサムとして機能する8を使う。生成されたシードとAD of (version || salt)を使って暗号化する。
  4. 最後にBIP-39のデフォルトのワードリストを使って、この33バイトの暗号テキストをエンコードし、24個の英単語を生成する。

こうやってプレーンテキストシード(19バイト)から暗号シード(33バイト)が生成される。

aezeed暗号シードの特性

aezeed暗号シード方式にはいくつかの特性がある。

  • mnemonic自体が暗号テキストから生成されているので、mnemonicだけ分かってもコインを盗むのは難しく、BIP-39でパスフレーズセットしていないとmnemonicが分かればコインが盗まれるのとは対照的。
  • パスフレーズを変更することで暗号シードを変更できる。ユーザーがより強力なパスフレーズを望む場合は、古いパスフレーズで復号し、次に新しいパスフレーズで暗号化することができる。BIP-39の場合、ユーザーがパスフレーズを使ったとしても、マッピングが一方向であるため、既存のHDキーチェーンのパスフレーズを変更することはできない。
  • 暗号シードをアップブレード可能。外部バージョンがあるので、オフラインツールを使って古いパラメータを復号し、新しいパラメータを使って暗号化することができる。将来暗号を変更したり、scryptを変更したり、scryptのパラメータのみを変更するば、ユーザーはオフラインツールでシードを簡単にアップグレードできる。

ウォレットの誕生日やバージョン情報の管理は、Lightningに限らずオンチェーンでも課題よね。

*1:BIP-39はHDウォレットのマスターシードを人間が覚えやすい単語リスト(mnemonic word)に変換する仕様を定義したBIP

Stratum protocol extensionsについて定義したBIP-310

Stratumはプールマイニングをサポートするマイニングプロトコルだが、その拡張の利用については長らく正式な規格を記述するBIPが無かったが、それをBIPとして定義したのがBIP-310↓

github.com

基本的には、Stratumサーバーとマイニングソフトウェアが接続された直後に、mining.configureメッセージを送信してサーバ/クライアント間でサポートしている拡張について認識し、利用する拡張について調整する仕組み。

BIP-310で定義されている拡張は以下の4つ。

  • version-rolling
  • minimum-difficulty
  • subscribe-extranonce
  • info

1つめのバージョンローリングは、こないだ書いたBIP-320の利用を前提としている(まぁ前提というか実際はもうそういう使い方されてる)。

techmedia-think.hatenablog.com

以下BIPに定義されているプロトコルの詳細↓

動機

Stratumプロトコルの拡張のサポートを指定する最初の動機は、マイナーにBitcoinのブロックヘッダの最初のフィールドの値を変更する「バージョンローリング」と呼ばれるものを許可することだった。

オリジナルのStratumプロトコルのバージョンではサーバーに異なるブロックバージョンの値を伝えることができなかったため、バージョンローリングはStratumプロトコル後方互換性がない。同様に、サーバーは安全なbitを使ってマイナーにローリングすることができなかった。したがってマイナーとプールの両方は、バージョンローリングをサポートするためにいつくかのプロトコル拡張を実装する必要がある。

通常、マイナーが未知のメッセージをサーバーに送信すると、サーバーは接続を閉じる(全てのサーバーが閉じるわけではないが、いくつかのサーバー実装ではそうなっている。)。そのため未知のメッセージをサーバーに送信することは安全ではない。

我々はこの機会を利用して、将来複数の拡張をサポートするためにプロトコルに対して後方互換性のない変更を行うことができる。マイナーがその能力を広告すると同時にサーバからいくつかの必要な機能を要求することができる。

機能のネゴシエーションのため同じ仕組みがまだ知られていない機能に対しても使用されることが望ましい。マイニングソフトウェアにも簡単に実装されるべきだ。

標準的な方法で機能の初期設定/ネゴシエーションを処理するstratumプロトコル(mining.configure)への新しいメッセージを1つ導入する。これにより将来、stratumプロトコルに新しいメッセージを追加することなく機能を追加することができる。

各拡張にはextension codeと呼ばれる一意の文字列名がある。

仕様

現在、以下の拡張が定義されている。

  • version-rolling
  • minimum-difficulty
  • subscribe-extranonce

追加のデータタイプ

以下の名称はタイプエイリアスとして使われ、メッセージの定義を簡単にする。

  • TMask
    32bitの符号なし整数([0-9a-fA-F]{8})をエンコードする長さ8の大文字小文字を区別しない16進文字列
  • TExtensionCode
    プロトコル拡張の名前と同じ値の空でない文字列
  • TExtensionResult
    true / false / String
    • true 要求された機能がサポートされ、その設定が理解でき適用される。
    • false この機能はサポートしていないか未知のもの
    • String 何がうまく行かなかったかに関する情報を含む文字列

mining.configure リクエス

このメッセージ(JSON RPCリクエスト)は、サーバーとの接続が確立された後にマイナーが送信する最初のメッセージである必要がある。クライアントはこのメッセージを使って自身がサポートする機能を宣伝し、いくつかのプロトコル拡張を要求/許可する。

最初の理由は、実装と可能な限りやりとりを簡単、シンプルにしたいからだ。拡張は、拡張の繰り返し設定が何を意味するか明示的に定義することができる。

各拡張コードは、その拡張パラメータや拡張の戻り値に対してネームスペースを提供する。慣例により、名称は拡張コードに”.”とパラメータ名を追加することで形成される。同様のことが戻り値にも適用され、result mapにも転送される。例えば「version-rolling.mask」は拡張「version-rolling」の「mask」というパラメータ名だ。

パラメータ
  • extensions(必須。TExtensionCodeのリスト)
    • リスト内の各文字列は有効な拡張コードでなければならない。各コードの意味は、拡張定義の一部として独立して記述される。マイナーは利用可能な全ての機能を広告しなければならない。
  • extension-parameters(必須。String -> 任意のデータのMap)
    • 最初のパラメータから要求/許可された拡張のパラメータ
戻り値
  • String -> 任意のデータのMap
    • 拡張リストの各コードは、定義された戻り値(TExtensionCode -> TExtensionResult)を持たなければならない。こうすることでマイナーは拡張が有効になっているかどうか確認することができる。例えばバージョンローリングをサポートしていない場合は{"version-rolling":false}
    • いくつかの拡張では、追加情報をマイナーに提供する必要がある。戻り値のMapはこのために使われる。

リクエストの例

{"method": "mining.configure",
  "id": 1,
  "params": [["minimum-difficulty", "version-rolling"],
         {"minimum-difficulty.value": 2048,
          "version-rolling.mask": "1fffe000", "version-rolling.min-bit-count": 2}]}

(マイナーは「version-rolling」と「minimum-difficulty」という拡張を要求する。この際、拡張の定義に従ってパラメータをセットする)

結果の例

{"error": null,
  "id": 1,
  "result": {"version-rolling": true,
         "version-rolling.mask": "18000000",
         "minimum-difficulty": true}}

定義された拡張

拡張「version-rolling」

この拡張によりマイナーはブロックヘッダのバージョンフィールドの一部のbitの値を変更できます。現在バージョンローリングに使用される標準bitは存在しないため、マイナーとサーバー間で調整する必要がある。

マイナーはマイナーが変更可能なbitを記述マスクをサーバーに送信する。1 = 変更可能なbit、0 = 変更不可能なbit (miner_mask)とバージョンローリングに必要な最小bit数。

サーバーは通常、version bits(server_mask)の一部のみを変更することができ、残りのversion bitsは固定されている。これは例えばブロックを有効なブロックにするためであったり、何らかのシグナリングに使われている場合があるためだ。

サーバーはコンフィギュレーションメッセージに応答し、マイナーのマスクとサーバーのマスクの共通bit交差を持つマスクを送信する(response = server_mask & miner_mask)。

リクエスト例(16bitのマスクから任意の2 bitを変更できるマイナー)

{"method": "mining.configure", "id": 1, "params": [["version-rolling"], {"version-rolling.mask": "1fffe000", "version-rolling.min-bit-count": 2}]}

結果の例(成功の場合)

{"error": null, "id": 1, "result": {"version-rolling": true, "version-rolling.mask": "18000000"}}

結果の例(未知の拡張の場合)

{"error": null, "id": 1, "result": {"version-rolling": false}}
拡張パラメータ
  • version-rolling.mask (オプション、TMask、デフォルト値は"ffffffff"
    • 1をセットされたbitは、マイナーによって変更することができる。この値はマイニングセッション全体で安定していることが期待される。マイナーはマスクを送信する必要はなく、この場合デフォルトのフルマスクが使用される。
拡張の戻り値
  • version-rolling(必須、TExtensionResult)
    • trueの場合サーバーは新しいパラメータmining.submitを受け取る(後述)。
  • version-rolling.mask(必須、TMask)
    • 1をセットされたbitは、マイナーによって変更することができる。マイナーがマスク値0のbitを変更した場合、サーバーは送信を拒否する。
    • サーバーは可能な限り最大のマスクを返すべきだ(可能な限り多くのbitが1に設定された)。これはプロキシが将来のクライアントに最適なマスクを調整する必要がある場合に、マイニングプロキシの設定に役立つ。利用可能なnVersion bitsについて記述したドラフトがある。サーバーはBIPで指定されたすべてのbitをカバーするマスクを作成するべきだ。
  • version-rolling.min-bit-count(必須、TMask)
    • マイナーはまたハードウェアでの効率的なバージョンローリングに必要な最小bit数も提供する。このパラメータはプールサーバに重要な診断情報を提供することに注意すること。要求されたbit数がプールサーバーの制限を超えた場合、ハッシュパワーを完全に使用することがない、常に劣化モードで動作する可能性がある。この稀なミスマッチが発生した場合、マイナーとの接続を終了してはならない。
「mining.set_version_mask」の通知

サーバーは接続に有効な新しいマスクについてマイナーに通知する。このメッセージは、mining.configureメッセージによりバージョンローリングの拡張が正常にセットアップされた後、いつでも送信できる。新しいマスクはすぐに有効になり、サーバーは次のジョブを待機しない。

パラメータ
  • mask(必須、TMask)
    意味はversion-rolling.mask 戻りパラメータと同じ。

サンプル

{"params":["00003000"], "id":null, "method": "mining.set_version_mask"}
mining.submit 要求の変更

バージョンローリング拡張が正常にアクティベートされた直後に(サーバーによって送信されたmining.configureの結果)、サーバーはメッセージmining.submitの追加パラメータを受け取らなければならない。クライアントは追加のパラメータversion_bitsを1つ送らなければならない(worker_name, job_id, extranonce2, ntime, nonceに続く6つめのパラメータとして)。

追加のパラメータ
  • version_bits(必須、TMask)
    マイナーによってセットされるversion bits。
    • マイナーはmining.configureもしくはmining.set_version_mask通知(last_mask)の応答として、サーバーから最後に受信したマスクの設定bitに対応するbitのみを設定できる。このためversion_bits & ~last_mask == 0となる
    • サーバーは次のように送信するnVersionを計算する。nVersion = (job_version & ~last_mask) | (version_bits & last_mask)job_versionjob_idと共にジョブの一部としてマイナーに送信されたブロックバージョン。

拡張「minimum-difficulty」

この拡張により、マイナーは接続されたマシンに最小難易度の要求をすることができる。これにより、接続されたデバイスのハードリミットを伝える方法がないオリジナルのStratumプロトコルの問題を解決する。

拡張パラメータ
  • minimum-difficulty.value(必須、Integer/Float, >= 0)
    マイナー/接続に許容される最小難易度の値。機能を無効にするには0をセットする。
拡張戻り値
  • minimum-difficulty(必須、TExtensionResult)
    • 最小難易度が受け入れられたかどうか
    • この拡張はminimum-difficultyコードを持つmining.configureを再度呼び出して複数回設定することができる。

拡張「subscribe-extranonce」

パラメータの無い拡張。マイナーはmining.set_extranonceメッセージを受信することができることを広告する(ハッシュレートルーティングシナリオに役立つ)。

拡張「info」

マイナーはテキストベースの追加情報を提供する。

拡張パラメータ
  • info.connection-url(オプション、文字列)
    マイニングソフトウェアがstratumサーバに接続するために使用する正確なURL。
  • info.hw-version(オプション、文字列)
    製造元固有のハードウェアバージョン文字列
  • info.sw-version(オプション、文字列)
    製造元固有のソフトウェアバージョン文字列
  • info.hw-id(オプション、文字列)
    マイニングデバイスの一意の識別子

互換性

現在、さまざまなプロトコル拡張を目的とした同様のプロトコル機能mining.capabilitiesが存在する。しかし、mining.configureは、全ての受け入れらた/調整中の拡張を確認するサーバーの応答を必要とするため、この機能と互換性がない。我々がこれを非互換にしたのは、mining.capabilitiesの要求には関連する応答がないためだ。