-
-
Save azuchi/8024402394fed65d58353092b1c15319 to your computer and use it in GitHub Desktop.
BIP-328に従ってMuSig2の集約公開鍵から子鍵を導出して子鍵に対する署名を生成
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'bitcoin' | |
| # 子鍵の導出処理(Bitcoin::ExtPubkeyにメソッドがあるけど、内部の調整値が後で必要になるので最低限必要な箇所だけ抽出) | |
| def derive(ext_key, number) | |
| new_key = Bitcoin::ExtPubkey.new | |
| new_key.depth = ext_key.depth + 1 | |
| new_key.number = number | |
| new_key.parent_fingerprint = ext_key.fingerprint | |
| data = ext_key.pub.htb << [number].pack('N') | |
| l = Bitcoin.hmac_sha512(ext_key.chain_code, data) | |
| left = l[0..31].bth.to_i(16) | |
| l_priv = ECDSA::Format::IntegerOctetString.encode(left, 32) | |
| p1 = Bitcoin::Key.new(priv_key: l_priv.bth, key_type: Bitcoin::Key::TYPES[:uncompressed]).to_point | |
| p2 = Bitcoin::Key.new(pubkey: ext_key.pubkey, key_type: ext_key.key_type).to_point | |
| new_key.pubkey = (p1 + p2).to_hex | |
| new_key.chain_code = l[32..-1] | |
| new_key.ver = ext_key.version | |
| [new_key, l_priv.bth] | |
| end | |
| # 2-of-2 マルチシグ | |
| alice = Bitcoin::Key.new(priv_key: 'e49aa7b20cec34e1d980c47a4be57978eae6748521b789bb417470c94c6c61c0') | |
| bob = Bitcoin::Key.new(priv_key: 'c306b555ec0dbbcd9c8c831ae65c0712b32bce1ad688c04931f3f24ab16e67bd') | |
| # 両者の公開鍵をソート | |
| participants = Schnorr::MuSig2.sort_pubkeys([alice.pubkey, bob.pubkey]) | |
| # 集約公開鍵を計算 | |
| agg_context = Schnorr::MuSig2.aggregate(participants) | |
| puts "agg_pubkey = #{agg_context.x_only_pubkey}" | |
| # 集約公開鍵を拡張公開鍵へ | |
| ext_key = Bitcoin::ExtPubkey.new | |
| ext_key.pubkey = agg_context.q.to_hex | |
| ext_key.depth = 0 | |
| ext_key.number = 0 | |
| ext_key.chain_code = '868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965'.htb | |
| ext_key.parent_fingerprint = Bitcoin::ExtKey::MASTER_FINGERPRINT | |
| # 拡張公開鍵/0/0の子鍵を導出 | |
| child_key, il_1 = derive(ext_key, 0) | |
| child_key, il_2 = derive(child_key, 0) | |
| # 子鍵導出の際に使用したI_Lは署名時の調整値に使用する | |
| tweaks = [il_1, il_2] | |
| # 調整値を適用する際のモード(調整時にx-only公開鍵を使うかプレーンな33バイトの公開鍵を使うかを決めるパラメーター) | |
| modes = [false, false] | |
| puts "child_key = #{child_key.key.xonly_pubkey}" | |
| # 導出した子鍵に対する集約署名の作成 | |
| msg = SecureRandom.bytes(32) # 署名対象の任意のメッセージ | |
| # アリスがnonceを生成 | |
| sec_nonce_alice, pub_nonce_alice = Schnorr::MuSig2.gen_nonce(pk: alice.pubkey) | |
| # ボブがnonceを生成 | |
| sec_nonce_bob, pub_nonce_bob = Schnorr::MuSig2.gen_nonce(pk: bob.pubkey) | |
| # 両者のpublic nonceから集約nonceを計算 | |
| agg_nonce = Schnorr::MuSig2.aggregate_nonce([pub_nonce_alice, pub_nonce_bob]) | |
| # 部分署名を生成を生成するセッションコンテキストを生成(ここで子鍵導出時の調整値をセット) | |
| session_ctx = Schnorr::MuSig2::SessionContext.new( | |
| agg_nonce, | |
| participants, | |
| msg, | |
| tweaks, | |
| modes | |
| ) | |
| # アリスが元の親鍵で部分署名 | |
| sig_alice = session_ctx.sign(sec_nonce_alice, alice.priv_key) | |
| # ボブが元の親鍵で部分署名 | |
| sig_bob = session_ctx.sign(sec_nonce_bob, bob.priv_key) | |
| # 部分署名を集約(この集約時に調整値が加味される) | |
| sig = session_ctx.aggregate_partial_sigs([sig_alice, sig_bob]) | |
| # 導出した子鍵に対して署名を検証 | |
| puts Schnorr.valid_sig?(msg, child_key.key.xonly_pubkey, sig.encode) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment