Created
December 24, 2019 16:27
-
-
Save kannapoix/8207fd1c5b4d69b398bfe98ea5480bb4 to your computer and use it in GitHub Desktop.
This file contains 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
# bip47 Pyament Code @ https://github.com/bitcoin/bips/blob/master/bip-0047.mediawiki#version-1 | |
# bitcoionrb @ https://github.com/chaintope/bitcoinrb | |
require 'bitcoin' | |
require 'ecdsa' | |
group = ECDSA::Group::Secp256k1 | |
include Bitcoin | |
include Bitcoin::Util | |
Bitcoin.chain_params = :mainnet | |
class ExtKeyPaymentCode | |
attr_accessor :ext_key, :payment_code | |
attr_writer :byte3_34, :byte35_66 | |
def initialize(seed=nil) | |
@bip32_master = Bitcoin::ExtKey.generate_master(seed) if seed | |
constants | |
genereate_payment_code if seed | |
end | |
def genereate_payment_code | |
# m/47'/0'/0' | |
@ext_key = @bip32_master.derive(47, harden=true).derive(0, harden=true).derive(0, harden=true) | |
chain_code = ext_key.chain_code | |
# first byte is odd prefix? | |
@byte3_34 = ext_key.pub.slice(2...ext_key.pub.length) # x of pubkey | |
@byte35_66 = chain_code.unpack('H*').first # chain code | |
@payment_code = Bitcoin::Base58.encode(row_payment_code + Bitcoin.calc_checksum(row_payment_code)) | |
end | |
def masked_payment_code(outpoint, shared_secret) | |
blinding_factor_string = blinding_factor(outpoint, shared_secret).first | |
x_xor = (@byte3_34.to_i(16)^blinding_factor_string[0..63].to_i(16)).to_s(16).rjust(64, '0') | |
c_xor = (@byte35_66.to_i(16)^blinding_factor_string[64..127].to_i(16)).to_s(16).rjust(64, '0') | |
# @prefix + @byte0 + @byte1 + @byte2 + x_xor + c_xor + @byte67_79 | |
@byte0 + @byte1 + @byte2 + x_xor + c_xor + @byte67_79 | |
end | |
def decode_masked_payment_code(outpoint, shared_secret, masked_payment_code) | |
p masked_payment_code | |
p byte3_34 = masked_payment_code[6, 64] | |
p byte35_66 = masked_payment_code[70, 64] | |
blinding_factor_string = blinding_factor(outpoint, shared_secret).first | |
@byte3_34 = (@byte3_34.to_i(16)^blinding_factor_string[0..63].to_i(16)).to_s(16).rjust(64, '0') | |
@byte35_66 = (@byte35_66.to_i(16)^blinding_factor_string[64..127].to_i(16)).to_s(16).rjust(64, '0') | |
row_payment_code | |
end | |
def row_payment_code | |
@prefix + @byte0 + @byte1 + @byte2 + @byte3_34 + @byte35_66 + @byte67_79 | |
end | |
def blinding_factor(outpoint, shared_secret) | |
Bitcoin.hmac_sha512([outpoint].pack("H*"), [shared_secret].pack("H*")).unpack("H*") | |
end | |
def shared_secret | |
alice_key = Bitcoin::Key.from_wif('Kx983SRhAZpAhj7Aac1wUXMJ6XZeyJKqCxJJ49dxEbYCT4a1ozRD') | |
alice_ec = OpenSSL::PKey::EC.new('secp256k1') | |
alice_ec.private_key = OpenSSL::BN.new(alice_key.priv_key, 16) | |
bob_payment_code = ExtKeyPaymentCode.new('87eaaac5a539ab028df44d9110defbef3797ddb805ca309f61a69ff96dbaa7ab5b24038cf029edec5235d933110f0aea8aeecf939ed14fc20730bba71e4b1110') | |
bob_payment_code_pub = bob_payment_code.ext_key.derive(0).pub | |
bob_pub_bn = OpenSSL::BN.new(bob_payment_code_pub, 16) | |
alice_secret_point = OpenSSL::PKey::EC::Point.new(alice_ec.group, bob_pub_bn) | |
# This is shared secret. | |
a_common_key = alice_ec.dh_compute_key(alice_secret_point).bth | |
end | |
def self.from_string hex_string | |
new_payment_code = new | |
new_payment_code.byte3_34 = hex_string[6, 64] | |
new_payment_code.byte35_66 = hex_string[70, 64] | |
new_payment_code | |
end | |
private | |
def constants | |
@prefix = '47' | |
@byte0 = '01' | |
@byte1 = '00' | |
@byte2 = '02' | |
@byte67_79 = '0' * 26 | |
end | |
end | |
Alice = ExtKeyPaymentCode.new('64dca76abc9c6f0cf3d212d248c380c4622c8f93b2c425ec6a5567fd5db57e10d3e6f94a2f6af4ac2edb8998072aad92098db73558c323777abf5bd1082d970a') | |
Bob = ExtKeyPaymentCode.new('87eaaac5a539ab028df44d9110defbef3797ddb805ca309f61a69ff96dbaa7ab5b24038cf029edec5235d933110f0aea8aeecf939ed14fc20730bba71e4b1110') | |
# Notification TX | |
# m/47'/0'/0'/0 | |
a = Alice.ext_key.derive(0).priv | |
A = Alice.ext_key.derive(0).pub | |
a_notification_address = Alice.ext_key.derive(0).key.to_p2pkh | |
p "alice notification private" | |
p a | |
p "alice notification pub" | |
p A | |
puts 'alice notification_address' | |
p a_notification_address | |
b = Bob.ext_key.derive(0).priv | |
B = Bob.ext_key.derive(0).pub | |
bob_notification = Bob.ext_key.derive(0).key | |
b_notification_address = bob_notification.to_p2pkh | |
p "bob notification private" | |
p b | |
p "bob notification pub" | |
p B | |
puts 'bob notification_address' | |
p b_notification_address | |
p | |
alice_key = Bitcoin::Key.from_wif('Kx983SRhAZpAhj7Aac1wUXMJ6XZeyJKqCxJJ49dxEbYCT4a1ozRD') | |
alice_ec = OpenSSL::PKey::EC.new('secp256k1') | |
alice_ec.private_key = OpenSSL::BN.new(alice_key.priv_key, 16) | |
alice_pub_bn = OpenSSL::BN.new(alice_key.pubkey, 16) | |
bob_ec = OpenSSL::PKey::EC.new('secp256k1') | |
bob_ec.private_key = OpenSSL::BN.new(b, 16) | |
bob_pub_bn = OpenSSL::BN.new(B, 16) | |
p alice_secret_point = OpenSSL::PKey::EC::Point.new(alice_ec.group, bob_pub_bn) | |
p bob_secret_point = OpenSSL::PKey::EC::Point.new(bob_ec.group, alice_pub_bn) | |
exit | |
# # This is shared secret. | |
a_common_key = alice_ec.dh_compute_key(alice_secret_point).bth | |
b_common_key = bob_ec.dh_compute_key(bob_secret_point).bth | |
p a_common_key == b_common_key | |
p a_common_key | |
p Alice.shared_secret | |
# # # o is outpoint | |
o = '86f411ab1c8e70ae8a0795ab7a6757aea6e4d5ae1826fc7b8f00c597d500609c01000000' | |
outpoint = Bitcoin::OutPoint.new('86f411ab1c8e70ae8a0795ab7a6757aea6e4d5ae1826fc7b8f00c597d500609c', 1) | |
# p "masked" | |
masked_payment_code = Alice.masked_payment_code(o, a_common_key) | |
notification_transaction = Bitcoin::Tx.new | |
input = Bitcoin::TxIn.new(out_point: outpoint) | |
notification_transaction.inputs[0] = input | |
script = Bitcoin::Script.new | |
script << Bitcoin::Opcodes::OP_RETURN << masked_payment_code | |
output = Bitcoin::TxOut.new script_pubkey: script | |
notification_transaction.outputs[0] = output | |
p new_tx | |
p new_tx.to_hex | |
# Make signature | |
a_pubkey = alice_key.pubkey | |
pubkey_hash = Bitcoin.hash160 a_pubkey | |
pubkey_script = Bitcoin::Script.to_p2pkh(pubkey_hash) | |
notification_transaction.in[0].script_sig = pubkey_script | |
p new_tx | |
signed_data = alice_key.sign(notification_transaction.to_hex) | |
notification_transaction.in[0].script_sig = Bitcoin::Script.from_string(signed_data) | |
notification_transaction.to_hex | |
p notification_transaction | |
masked_payment_code = notification_transaction.out[0].script_pubkey.op_return_data.bth | |
alice_payment_code_by_bob = ExtKeyPaymentCode.from_string(masked_payment_code).decode_masked_payment_code(o, a_common_key, masked_payment_code) | |
a_payment_code = Alice.row_payment_code | |
alice_payment_code_by_bob == a_payment_code | |
# Alice to Bob Payment | |
## Alice selects the 0th private key derived from her payment code: | |
## this a is correct! | |
a | |
## Alice selects the next unused public key derived from Bob's payment code, starting from zero: | |
## this bobpub is correct! | |
bobpub = Bob.ext_key.ext_pubkey.derive(0).pubkey | |
bob_pub_bn = OpenSSL::BN.new(bobpub, 16) | |
## Alice calculates a secret point: | |
# a*B | |
alice_ec = OpenSSL::PKey::EC.new('secp256k1') | |
alice_ec.private_key = OpenSSL::BN.new(a, 16) | |
alice_secret_point = OpenSSL::PKey::EC::Point.new(alice_ec.group, bob_pub_bn) | |
large_s = alice_ec.dh_compute_key(alice_secret_point) | |
## Alice calculates a scalar shared secret using the x value of S: | |
# p sx = Key.new(pubkey: large_s).to_point | |
# this s is correct!!! | |
s = Bitcoin::Util.sha256(large_s).bth | |
## B + sG | |
### sG ? | |
# sg = Key.new(priv_key: s, compressed: false) | |
p sg = Key.new(priv_key: s) | |
# p sg == '0283850c6835576554261fbab5845a099638859528b2725455e6a48e7566415c02' | |
p sg_point = sg.to_point | |
# sg = OpenSSL::PKey::EC::Point.new(bob_ec.group, OpenSSL::BN.new(s.bth, 16)) | |
### B=bob_pub_point | |
# bob_pub_point = OpenSSL::PKey::EC::Point.new(bob_ec.group, bob_pub_bn) | |
p bob_pub_point = Bob.ext_key.derive(0).key.to_point | |
p bob_pub_point.x.to_s(16) | |
p b_prime = bob_pub_point + sg_point | |
p b_prime.x.to_s(16) | |
p b_prime.x.to_s(16) == '0344b4795e48df097bd87e6cf87a70e4f0c30b2d847b6e34cddde64af10296952d' | |
## 03 が必要だった.... | |
b_prime = '03' + b_prime.x.to_s(16) | |
key = Key.new(pubkey: b_prime) | |
p key.to_p2pkh == '141fi7TY3h936vRUKh1qfUZr8rSBuYbVBK' | |
# 141fi7TY3h936vRUKh1qfUZr8rSBuYbVBK |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment