Skip to content

Instantly share code, notes, and snippets.

@azuchi
Created May 6, 2018 06:51
Show Gist options
  • Save azuchi/20317f760a9b07e4cd73ec1e79999aa5 to your computer and use it in GitHub Desktop.
Save azuchi/20317f760a9b07e4cd73ec1e79999aa5 to your computer and use it in GitHub Desktop.
ECDSAでTaprootを構成した際のPの署名を生成するコード
# ECDSAでTaprootを構成した際のPの署名を生成するコード
require 'bitcoin'
require 'paillier'
include Bitcoin::Opcodes
point_field = ECDSA::PrimeField.new(ECDSA::Group::Secp256k1.order)
# アリスが鍵ペアを生成
alice_key = Bitcoin::Key.generate
alice_pub = alice_key.to_point
# ボブが鍵ペアを生成
bob_key = Bitcoin::Key.generate
bob_pub = bob_key.to_point
alternative = (Bitcoin::Script.new << 1000 << OP_CHECKSEQUENCEVERIFY << OP_DROP << bob_key.pubkey << OP_CHECKSIG).to_payload
# ロック先のマルチシグ用の公開鍵
c = bob_pub.multiply_by_scalar(alice_key.priv_key.to_i(16))
hash = point_field.mod(Bitcoin.sha256(ECDSA::Format::PointOctetString.encode(c, compression: true).bth + alternative.bth).bth.to_i(16))
P = c + ECDSA::Group::Secp256k1.new_point(hash)
# アリスはランダムなnonceを生成
alice_r = Bitcoin::Key.generate
alice_R = alice_r.to_point
# ボブはランダムなnonceを生成
bob_r = Bitcoin::Key.generate
bob_R = bob_r.to_point
# アリスはボブのナンスの点と自分のrを使ってRを計算
aR = bob_R.multiply_by_scalar(alice_r.priv_key.to_i(16))
# ボブはアリスのナンスの点と自分のrを使ってRを計算
bR = alice_R.multiply_by_scalar(bob_r.priv_key.to_i(16))
# 共通の点のx座標
r = point_field.mod(aR.x)
# メッセージ(実際にはマルチシグにロックされたコインを使用するトランザクションのsighashになる)
m = Bitcoin.sha256('message'.htb)
e = ECDSA.normalize_digest(m, ECDSA::Group::Secp256k1.bit_length)
# アリスはPaillier暗号の鍵ペアを生成する
privkey, pubkey = Paillier.generateKeypair(2048)
# アリスはckeyを生成してボブに渡す
ckey = Paillier.encrypt(pubkey, alice_key.priv_key.to_i(16))
# ボブはc1,c2を計算する。
pq = Paillier::Primes.generatePrime(1024) * ECDSA::Group::Secp256k1.order
c1 = Paillier.encrypt(pubkey, point_field.mod(point_field.inverse(bob_r.priv_key.to_i(16)) * (e)) + pq)
c2 = Paillier.eMulConst(pubkey, ckey, point_field.mod(bob_key.priv_key.to_i(16) * r * point_field.inverse(bob_r.priv_key.to_i(16))))
c2 = Paillier.eAddConst(pubkey, c2, hash * r * point_field.inverse(bob_r.priv_key.to_i(16)))
c3 = Paillier.eAdd(pubkey, c1, c2)
# アリスはc3を復号する。
s_dash = Paillier.decrypt(privkey, pubkey, c3)
# アリスは復号したデータから署名に必要なsを計算する。
s = point_field.mod(s_dash * point_field.inverse(alice_r.priv_key.to_i(16))).to_i
# 署名データとしてエンコード
signature = ECDSA::Format::SignatureDerString.encode(ECDSA::Signature.new(r, s))
# 実際にPで検証
multisig_pubkey = Bitcoin::Key.new(pubkey: ECDSA::Format::PointOctetString.encode(P, compression: true).bth)
puts multisig_pubkey.verify(signature, m)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment