Skip to content

Commit

Permalink
Support BIP-322 full scheme verification in Bitcoin::MessageSign#veri…
Browse files Browse the repository at this point in the history
…fy_message
  • Loading branch information
azuchi committed Aug 21, 2024
1 parent 112e9ef commit ce54672
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
23 changes: 21 additions & 2 deletions lib/bitcoin/message_sign.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,18 @@ def verify_message(address, signature, message, prefix: Bitcoin.chain_params.mes
end
elsif addr_script.witness_program?
# BIP322 verification
tx = to_sign_tx(message_hash(message, prefix: prefix, legacy: false), address)
tx.in[0].script_witness = Bitcoin::ScriptWitness.parse_from_payload(sig)
digest = message_hash(message, prefix: prefix, legacy: false)
begin
# Full
tx = Bitcoin::Tx.parse_from_payload(sig)
validate_to_sign_tx!(tx)
to_spend = to_spend_tx(digest, address)
return false unless tx.in[0].out_point.tx_hash == to_spend.tx_hash
rescue Exception
# Simple
tx = to_sign_tx(digest, address)
tx.in[0].script_witness = Bitcoin::ScriptWitness.parse_from_payload(sig)
end
script_pubkey = Bitcoin::Script.parse_from_addr(address)
tx_out = Bitcoin::TxOut.new(script_pubkey: script_pubkey)
flags = Bitcoin::STANDARD_SCRIPT_VERIFY_FLAGS
Expand Down Expand Up @@ -99,6 +109,14 @@ def validate_format!(format)
end
end

def validate_to_sign_tx!(tx)
raise ArgumentError, "Multiple inputs (proof of funds) are not supported." unless tx.in.length == 1
raise ArgumentError, "vin[0].prevout.n must be 0." unless tx.in[0].out_point.index == 0
raise ArgumentError, "Multiple outputs are not supported." unless tx.out.length == 1
raise ArgumentError, "vout[0].nValue must be 0." unless tx.out[0].value == 0
raise ArgumentError, "vout[0].scriptPubKey must be OP_RETURN." unless tx.out[0].script_pubkey == Bitcoin::Script.new << Bitcoin::Opcodes::OP_RETURN
end

def to_spend_tx(digest, addr)
validate_address!(addr)
message_challenge = Bitcoin::Script.parse_from_addr(addr)
Expand All @@ -124,5 +142,6 @@ def to_sign_tx(digest, addr)

private_class_method :validate_address!
private_class_method :validate_format!
private_class_method :validate_to_sign_tx!
end
end
7 changes: 7 additions & 0 deletions spec/bitcoin/message_sign_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
format: described_class::FORMAT_SIMPLE,
address: addr)
expect(sig1).to eq('AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=')
sig1_full = described_class.sign_message(
private_key,
'',
format: described_class::FORMAT_FULL,
address: addr)
sig2 = described_class.sign_message(
private_key,
'Hello World',
Expand All @@ -130,6 +135,8 @@
expect(described_class.verify_message(addr, sig1, '')).to be true
expect(described_class.verify_message(addr, sig2, 'Hello World')).to be true
expect(described_class.verify_message(addr, sig2, 'Hello World2')).to be false
expect(described_class.verify_message(addr, sig1_full, '')).to be true
expect(described_class.verify_message(addr, sig1_full, 'Hello')).to be false
end
end

Expand Down

0 comments on commit ce54672

Please sign in to comment.