先日マージされたBIP-328↓は、
https://github.com/bitcoin/bips/blob/master/bip-0328.mediawiki
MuSig2の集約公開鍵をベースに新たな子鍵を導出するためのスキームを定義した仕様になる。
MuSig2は、n-of-nのマルチシグに参加する複数の参加者の鍵を1つの公開鍵に集約し、署名も各参加者が自身の秘密鍵を使って計算した部分署名を集約することで、集約公開鍵に対する有効なSchnorr署名を作成する署名スキーム。Bitcoinで使用する際は、BIP-327でその署名スキームが定義されている。
BIP-328の目的
MuSig2自体で公開鍵と署名の集約が可能になるものの、同じ参加者で複数回に渡って支払いなどを行う場合、オンチェーン支払いのプライバシーを考慮すると、支払いの都度新しいアドレスが生成されるのが望ましい。
マルチシグでなく一人の場合は、単純にHDウォレット(BIP-32)を使って、支払いの度に拡張鍵から新しい子鍵を導出していけばいい。
マルチシグの場合もシングルシグと同様に各参加者がそれぞれ拡張鍵から子鍵を導出し、全参加者の子鍵を集めれば新しいアドレスが導出できる。ただ、全参加者が子鍵を導出してそれを集約するよりも、単一の拡張公開鍵から導出できた方が簡単。そこで、MuSig2の集約公開鍵から子鍵を導出できるようにしようというのがBIP-328の狙い。
仕様
MuSig2の集約公開鍵は通常の公開鍵なので、新たな子鍵を導出できるようにBIP-32の拡張公開鍵にする必要がある。BIPでは、これをsynthetic xpubと呼んでる。
拡張公開鍵にするにあたって、集約公開鍵に適用される必要な値として以下が定義されている。
- depth:
0 - 子の番号:
0 - chaincode:
868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965(テキストMuSig2MuSig2MuSig2のSHA256ハッシュ値)
※ BIPには定義されてないけど、シリアライゼーションする場合は必要になる親のfingerprintはマスター鍵と同様に00000000セットしとけばいいのかな?
親公開鍵から子公開鍵の導出は、BIP-32の関数が使われる。この関数では以下の計算により子公開鍵が導出される(簡易的な記述で、エラーチェック含む詳細はBIP-32参照)。
- 親のchaincodeと、
親の公開鍵||導出インデックスからHMAC-SHA256を計算し(計算結果をIとする)、 - 1の前半32バイト(
)を秘密鍵として公開鍵
を計算し、その公開鍵に親公開鍵を加算した点が子公開鍵になる。
- 1の後半32バイト(
)は子のchaincodeとなる。
子公開鍵を導出するためには親の公開鍵と親のchaincodeが必要になる(↑の定義値を使用)。これで、子拡張公開鍵が導出できるので、それ以降はBIP-32の仕様に従って階層的に新たな鍵を導出することができる。
なお、集約公開鍵から導出してるので秘密鍵を必要とする強化導出はできない。
導出した子鍵に対する署名を作成する際は、各署名者は署名対象の子鍵の導出時の調整値(↑の)を計算する必要があり、MuSig2のセッションコンテキストで共有される。
実際にbitcoinrbを使って実装してみた↓