OP_CHECKDATASIG

Tapyrus の OP_CHECKDATASIG について。

Bitcoin Cash からの輸入らしい。元はトランザクションの署名検証にSchnorr署名を利用するため・オラクルのサポートのために導入されたものっぽい。

使い方

<sig> <msg> <pubKey> OP_CHECKDATASIG
require 'tapyrus' include Tapyrus::Opcodes key = Tapyrus::Key.generate message = 'hogehoge' message_hex = message.bth digest = Tapyrus.sha256(message_hex) signature = key.sign(digest) script = Tapyrus::Script.new << signature << message_hex << key.pubkey << OP_CHECKDATASIG script.run # => true

試す

P2SHに仕込む

require 'tapyrus' include Tapyrus::Opcodes Tapyrus.chain_params = :dev TAPYRUS_DEV_AGGREGATE_PRIV_KEY = "cUJN5RVzYWFoeY8rUztd47jzXCu1p57Ay8V7pqCzsBD3PEXN7Dd4" TAPYRUS_RPC_CONFIG = { schema: 'http', host: 'localhost', port: 12381, user: 'rpcuser', password: 'rpcpassword' } TAPYRUS_RPC_CLIENT = Tapyrus::RPC::TapyrusCoreClient.new(TAPYRUS_RPC_CONFIG) FEE = 0.00003 key = Tapyrus::Key.generate message = 'hogehoge' # Prepare fund TAPYRUS_RPC_CLIENT.generatetoaddress(1, TAPYRUS_RPC_CLIENT.getnewaddress, TAPYRUS_DEV_AGGREGATE_PRIV_KEY) fund_utxo = TAPYRUS_RPC_CLIENT.listunspent.find {|utxo| utxo['amount'].to_i > 3 && utxo['token'] == 'TPC' } fund_tx = Tapyrus::Tx.parse_from_payload(TAPYRUS_RPC_CLIENT.getrawtransaction(fund_utxo['txid']).htb) fund_outpoint = Tapyrus::OutPoint.from_txid(fund_utxo['txid'], fund_utxo['vout']) # P2SH as ScriptPubkey redeem_script = Tapyrus::Script.new << message.bth << key.pubkey << OP_CHECKDATASIG p2sh = redeem_script.to_p2sh p2sh_amount = 1 # Create transaction tx = Tapyrus::Tx.new tx.in << Tapyrus::TxIn.new(out_point: fund_outpoint) input_tapyrus = (fund_utxo['amount'].to_f * (10**8)).to_i fee_tapyrus = (FEE * (10**8)).to_i amount_tapyrus = (p2sh_amount * (10**8)).to_i change_tapyrus = input_tapyrus - amount_tapyrus - fee_tapyrus tx.out << Tapyrus::TxOut.new(value: amount_tapyrus, script_pubkey: p2sh) tx.out << Tapyrus::TxOut.new(value: change_tapyrus, script_pubkey: Tapyrus::Script.parse_from_addr(TAPYRUS_RPC_CLIENT.getnewaddress)) # Sign fund_utxo_script_pubkey = fund_tx.outputs[fund_utxo['vout'].to_i].script_pubkey fund_utxo_key = Tapyrus::Key.from_wif(TAPYRUS_RPC_CLIENT.dumpprivkey(fund_utxo_script_pubkey.to_addr)) sig_hash = tx.sighash_for_input(0, fund_utxo_script_pubkey) signature = fund_utxo_key.sign(sig_hash) + [Tapyrus::SIGHASH_TYPE[:all]].pack('C') tx.in[0].script_sig << signature tx.in[0].script_sig << fund_utxo_key.pubkey.htb raise StandardError unless tx.verify_input_sig(0, fund_utxo_script_pubkey) # => nil # Broadcast P2SH transaction p2sh_txid = TAPYRUS_RPC_CLIENT.sendrawtransaction(tx.to_payload.bth) TAPYRUS_RPC_CLIENT.generatetoaddress(1, TAPYRUS_RPC_CLIENT.getnewaddress, TAPYRUS_DEV_AGGREGATE_PRIV_KEY) p2sh_tx = Tapyrus::Tx.parse_from_payload(TAPYRUS_RPC_CLIENT.getrawtransaction(p2sh_txid).htb) p2sh_utxo = p2sh_tx.outputs.first p2sh_out_point = Tapyrus::OutPoint.from_txid(p2sh_txid, 0) # ======================================================================================= # Create signature signature = key.sign(Tapyrus.sha256(message.bth)) # Create transaction tx = Tapyrus::Tx.new tx.in << Tapyrus::TxIn.new(out_point: p2sh_out_point) input_tapyrus = p2sh_utxo.value fee_tapyrus = (FEE * (10**8)).to_i amount_tapyrus = (0.5 * (10**8)).to_i change_tapyrus = input_tapyrus - amount_tapyrus - fee_tapyrus tx.out << Tapyrus::TxOut.new(value: amount_tapyrus, script_pubkey: Tapyrus::Script.parse_from_addr(TAPYRUS_RPC_CLIENT.getnewaddress)) tx.out << Tapyrus::TxOut.new(value: change_tapyrus, script_pubkey: Tapyrus::Script.parse_from_addr(TAPYRUS_RPC_CLIENT.getnewaddress)) # ScriptSig script_sig = Tapyrus::Script.new << signature << redeem_script.to_payload.bth tx.in[0].script_sig = script_sig raise StandardError unless tx.verify_input_sig(0, p2sh) # => nil spent_p2sh_txid = TAPYRUS_RPC_CLIENT.sendrawtransaction(tx.to_payload.bth) TAPYRUS_RPC_CLIENT.generatetoaddress(1, TAPYRUS_RPC_CLIENT.getnewaddress, TAPYRUS_DEV_AGGREGATE_PRIV_KEY)