bitcoinrb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bitcoinrb.gemspec +32 -0
- data/exe/bitcoinrb-cli +5 -0
- data/exe/bitcoinrbd +49 -0
- data/lib/bitcoin.rb +121 -0
- data/lib/bitcoin/base58.rb +40 -0
- data/lib/bitcoin/block_header.rb +41 -0
- data/lib/bitcoin/chain_params.rb +57 -0
- data/lib/bitcoin/chainparams/mainnet.yml +25 -0
- data/lib/bitcoin/chainparams/regtest.yml +20 -0
- data/lib/bitcoin/chainparams/testnet.yml +24 -0
- data/lib/bitcoin/connection.rb +66 -0
- data/lib/bitcoin/ext_key.rb +205 -0
- data/lib/bitcoin/key.rb +131 -0
- data/lib/bitcoin/logger.rb +18 -0
- data/lib/bitcoin/merkle_tree.rb +120 -0
- data/lib/bitcoin/message.rb +42 -0
- data/lib/bitcoin/message/addr.rb +74 -0
- data/lib/bitcoin/message/base.rb +40 -0
- data/lib/bitcoin/message/block.rb +41 -0
- data/lib/bitcoin/message/error.rb +10 -0
- data/lib/bitcoin/message/fee_filter.rb +27 -0
- data/lib/bitcoin/message/filter_add.rb +28 -0
- data/lib/bitcoin/message/filter_clear.rb +17 -0
- data/lib/bitcoin/message/filter_load.rb +43 -0
- data/lib/bitcoin/message/get_addr.rb +17 -0
- data/lib/bitcoin/message/get_blocks.rb +29 -0
- data/lib/bitcoin/message/get_data.rb +21 -0
- data/lib/bitcoin/message/get_headers.rb +28 -0
- data/lib/bitcoin/message/handler.rb +170 -0
- data/lib/bitcoin/message/headers.rb +34 -0
- data/lib/bitcoin/message/headers_parser.rb +24 -0
- data/lib/bitcoin/message/inv.rb +21 -0
- data/lib/bitcoin/message/inventories_parser.rb +23 -0
- data/lib/bitcoin/message/inventory.rb +47 -0
- data/lib/bitcoin/message/mem_pool.rb +17 -0
- data/lib/bitcoin/message/merkle_block.rb +42 -0
- data/lib/bitcoin/message/not_found.rb +29 -0
- data/lib/bitcoin/message/ping.rb +30 -0
- data/lib/bitcoin/message/pong.rb +26 -0
- data/lib/bitcoin/message/reject.rb +46 -0
- data/lib/bitcoin/message/send_cmpct.rb +43 -0
- data/lib/bitcoin/message/send_headers.rb +16 -0
- data/lib/bitcoin/message/tx.rb +30 -0
- data/lib/bitcoin/message/ver_ack.rb +17 -0
- data/lib/bitcoin/message/version.rb +79 -0
- data/lib/bitcoin/mnemonic.rb +76 -0
- data/lib/bitcoin/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/english.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/french.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/italian.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/japanese.txt +2048 -0
- data/lib/bitcoin/mnemonic/wordlist/spanish.txt +2048 -0
- data/lib/bitcoin/nodes.rb +5 -0
- data/lib/bitcoin/nodes/spv.rb +13 -0
- data/lib/bitcoin/nodes/spv/cli.rb +12 -0
- data/lib/bitcoin/nodes/spv/daemon.rb +21 -0
- data/lib/bitcoin/opcodes.rb +172 -0
- data/lib/bitcoin/out_point.rb +31 -0
- data/lib/bitcoin/script/script.rb +347 -0
- data/lib/bitcoin/script/script_error.rb +168 -0
- data/lib/bitcoin/script/script_interpreter.rb +694 -0
- data/lib/bitcoin/script/tx_checker.rb +44 -0
- data/lib/bitcoin/script_witness.rb +29 -0
- data/lib/bitcoin/secp256k1.rb +10 -0
- data/lib/bitcoin/secp256k1/native.rb +22 -0
- data/lib/bitcoin/secp256k1/ruby.rb +96 -0
- data/lib/bitcoin/tx.rb +191 -0
- data/lib/bitcoin/tx_in.rb +45 -0
- data/lib/bitcoin/tx_out.rb +32 -0
- data/lib/bitcoin/util.rb +105 -0
- data/lib/bitcoin/version.rb +3 -0
- metadata +256 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
|
3
|
+
# Block Header
|
4
|
+
class BlockHeader
|
5
|
+
|
6
|
+
attr_accessor :hash
|
7
|
+
attr_accessor :version
|
8
|
+
attr_accessor :prev_hash
|
9
|
+
attr_accessor :merkle_root
|
10
|
+
attr_accessor :time
|
11
|
+
attr_accessor :bits
|
12
|
+
attr_accessor :nonce
|
13
|
+
|
14
|
+
def initialize(version, prev_hash, merkle_root, time, bits, nonce)
|
15
|
+
@version = version
|
16
|
+
@prev_hash = prev_hash
|
17
|
+
@merkle_root = merkle_root
|
18
|
+
@time = time
|
19
|
+
@bits = bits
|
20
|
+
@nonce = nonce
|
21
|
+
@hash = calc_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_from_payload(payload)
|
25
|
+
version, prev_hash, merkle_root, time, bits, nonce = payload.unpack('Va32a32VVV')
|
26
|
+
new(version, prev_hash.reverse.bth, merkle_root.reverse.bth, time, bits, nonce)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_payload
|
30
|
+
[version, prev_hash.htb.reverse, merkle_root.htb.reverse, time, bits, nonce].pack('Va32a32VVV')
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def calc_hash
|
36
|
+
Bitcoin.double_sha256(to_payload).reverse.bth
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
|
5
|
+
# Network parameter class
|
6
|
+
class ChainParams
|
7
|
+
|
8
|
+
attr_reader :network
|
9
|
+
attr_reader :magic_head
|
10
|
+
attr_reader :message_magic
|
11
|
+
attr_reader :address_version
|
12
|
+
attr_reader :p2sh_version
|
13
|
+
attr_reader :bech32_hrp
|
14
|
+
attr_reader :privkey_version
|
15
|
+
attr_reader :extended_privkey_version
|
16
|
+
attr_reader :extended_pubkey_version
|
17
|
+
attr_reader :default_port
|
18
|
+
attr_reader :protocol_version
|
19
|
+
attr_reader :retarget_interval
|
20
|
+
attr_reader :retarget_time
|
21
|
+
attr_reader :target_spacing
|
22
|
+
attr_reader :max_money
|
23
|
+
attr_reader :bip34_height
|
24
|
+
attr_reader :genesis_hash
|
25
|
+
attr_reader :proof_of_work_limit
|
26
|
+
attr_reader :dns_seeds
|
27
|
+
|
28
|
+
# mainnet params
|
29
|
+
def self.mainnet
|
30
|
+
YAML.load(File.open("#{__dir__}/chainparams/mainnet.yml"))
|
31
|
+
end
|
32
|
+
|
33
|
+
# testnet params
|
34
|
+
def self.testnet
|
35
|
+
YAML.load(File.open("#{__dir__}/chainparams/testnet.yml"))
|
36
|
+
end
|
37
|
+
|
38
|
+
# regtest params
|
39
|
+
def self.regtest
|
40
|
+
YAML.load(File.open("#{__dir__}/chainparams/regtest.yml"))
|
41
|
+
end
|
42
|
+
|
43
|
+
def mainnet?
|
44
|
+
network == 'mainnet'
|
45
|
+
end
|
46
|
+
|
47
|
+
def testnet?
|
48
|
+
network == 'testnet'
|
49
|
+
end
|
50
|
+
|
51
|
+
def regtest?
|
52
|
+
network == 'regtest'
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
--- !ruby/object:Bitcoin::ChainParams
|
2
|
+
network: "mainnet"
|
3
|
+
magic_head: "f9beb4d9"
|
4
|
+
message_magic: "Bitcoin Signed Message:\n"
|
5
|
+
address_version: "00"
|
6
|
+
p2sh_version: "05"
|
7
|
+
bech32_hrp: 'bc'
|
8
|
+
privkey_version: "80"
|
9
|
+
extended_privkey_version: "0488ade4"
|
10
|
+
extended_pubkey_version: "0488b21e"
|
11
|
+
default_port: 8333
|
12
|
+
protocol_version: 70013
|
13
|
+
retarget_interval: 2016
|
14
|
+
retarget_time: 1209600 # 2 weeks
|
15
|
+
target_spacing: 600 # block interval
|
16
|
+
max_money: 21000000
|
17
|
+
bip34_height: 227931
|
18
|
+
genesis_hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
19
|
+
proof_of_work_limit: 0x1d00ffff
|
20
|
+
dns_seeds:
|
21
|
+
- "seed.bitcoin.sipa.be"
|
22
|
+
- "dnsseed.bluematt.me"
|
23
|
+
- "dnsseed.bitcoin.dashjr.org"
|
24
|
+
- "seed.bitcoinstats.com"
|
25
|
+
- "seed.bitcoin.jonasschnelli.ch"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
--- !ruby/object:Bitcoin::ChainParams
|
2
|
+
network: "regtest"
|
3
|
+
magic_head: "fabfb5da"
|
4
|
+
message_magic: "Bitcoin Signed Message:\n"
|
5
|
+
address_version: "6f"
|
6
|
+
p2sh_version: "c4"
|
7
|
+
bech32_hrp: 'tb'
|
8
|
+
privkey_version: "ef"
|
9
|
+
extended_privkey_version: "04358394"
|
10
|
+
extended_pubkey_version: "043587cf"
|
11
|
+
default_port: 18444
|
12
|
+
protocol_version: 70013
|
13
|
+
retarget_interval: 2016
|
14
|
+
retarget_time: 1209600 # 2 weeks
|
15
|
+
target_spacing: 600 # block interval
|
16
|
+
max_money: 21000000
|
17
|
+
bip34_height: 0
|
18
|
+
genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
19
|
+
proof_of_work_limit: 0x207fffff
|
20
|
+
dns_seeds:
|
@@ -0,0 +1,24 @@
|
|
1
|
+
--- !ruby/object:Bitcoin::ChainParams
|
2
|
+
network: "testnet"
|
3
|
+
magic_head: "0b110907"
|
4
|
+
message_magic: "Bitcoin Signed Message:\n"
|
5
|
+
address_version: "6f"
|
6
|
+
p2sh_version: "c4"
|
7
|
+
bech32_hrp: 'tb'
|
8
|
+
privkey_version: "ef"
|
9
|
+
extended_privkey_version: "04358394"
|
10
|
+
extended_pubkey_version: "043587cf"
|
11
|
+
default_port: 18333
|
12
|
+
protocol_version: 70013
|
13
|
+
retarget_interval: 2016
|
14
|
+
retarget_time: 1209600 # 2 weeks
|
15
|
+
target_spacing: 600 # block interval
|
16
|
+
max_money: 21000000
|
17
|
+
bip34_height: 227931
|
18
|
+
genesis_hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
19
|
+
proof_of_work_limit: 0x1d00ffff
|
20
|
+
dns_seeds:
|
21
|
+
- "testnet-seed.bitcoin.jonasschnelli.ch"
|
22
|
+
- "seed.tbtc.petertodd.org"
|
23
|
+
- "testnet-seed.bluematt.me"
|
24
|
+
- "testnet-seed.bitcoin.schildbach.de"
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
|
3
|
+
# Basic Bitcoin P2P connection class
|
4
|
+
class Connection < EM::Connection
|
5
|
+
|
6
|
+
attr_reader :host, :port, :handler, :logger
|
7
|
+
attr_accessor :connected
|
8
|
+
|
9
|
+
# if true, this peer send new block announcements using a headers message rather than an inv message.
|
10
|
+
attr_accessor :sendheaders
|
11
|
+
|
12
|
+
# minimum fee(in satoshis per kilobyte) for relay tx
|
13
|
+
attr_accessor :fee_rate
|
14
|
+
|
15
|
+
def initialize(host, port)
|
16
|
+
@host = host
|
17
|
+
@port = port
|
18
|
+
@logger = Bitcoin::Logger.create(:connection)
|
19
|
+
@handler = Message::Handler.new(self, @logger)
|
20
|
+
@connected = false
|
21
|
+
@sendheaders = false
|
22
|
+
@attr_accessor = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def post_init
|
26
|
+
logger.info "connected. #{remote_node}"
|
27
|
+
begin_handshake
|
28
|
+
end
|
29
|
+
|
30
|
+
# handle receiving data from remote node.
|
31
|
+
def receive_data(data)
|
32
|
+
logger.info "receive data from #{remote_node}, data : #{data}"
|
33
|
+
handler.handle(data)
|
34
|
+
end
|
35
|
+
|
36
|
+
# close network connection.
|
37
|
+
def close(msg = '')
|
38
|
+
logger.info "close connection with #{remote_node}. #{msg}"
|
39
|
+
close_connection_after_writing
|
40
|
+
EM.stop
|
41
|
+
end
|
42
|
+
|
43
|
+
def handshake_done
|
44
|
+
logger.info 'handshake finished.'
|
45
|
+
@connected = true
|
46
|
+
# send_data(Message::SendCmpct.new(0, 1))
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def remote_node
|
53
|
+
"#{host}:#{port}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# start handshake
|
57
|
+
def begin_handshake
|
58
|
+
logger.info "begin handshake with #{remote_node}"
|
59
|
+
ver = Bitcoin::Message::Version.new(remote_addr: remote_node, start_height: 1150660)
|
60
|
+
logger.info "send version message. #{ver.to_json}"
|
61
|
+
send_data(ver.to_pkt)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
|
3
|
+
def self.hmac_sha512(key, data)
|
4
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA512'), key, data)
|
5
|
+
end
|
6
|
+
|
7
|
+
# Integers modulo the order of the curve(secp256k1)
|
8
|
+
CURVE_ORDER = 115792089237316195423570985008687907852837564279074904382605163141518161494337
|
9
|
+
|
10
|
+
# BIP32 Extended private key
|
11
|
+
class ExtKey
|
12
|
+
|
13
|
+
attr_accessor :depth
|
14
|
+
attr_accessor :number
|
15
|
+
attr_accessor :chain_code
|
16
|
+
attr_accessor :key
|
17
|
+
attr_accessor :parent_fingerprint
|
18
|
+
|
19
|
+
# generate master key from seed.
|
20
|
+
def self.generate_master(seed)
|
21
|
+
ext_key = ExtKey.new
|
22
|
+
ext_key.depth = ext_key.number = 0
|
23
|
+
ext_key.parent_fingerprint = '00000000'
|
24
|
+
l = Bitcoin.hmac_sha512('Bitcoin seed', seed)
|
25
|
+
left = l[0..31].bth.to_i(16)
|
26
|
+
raise 'invalid key' if left >= CURVE_ORDER || left == 0
|
27
|
+
ext_key.key = Bitcoin::Key.new(priv_key: l[0..31].bth)
|
28
|
+
ext_key.chain_code = l[32..-1]
|
29
|
+
ext_key
|
30
|
+
end
|
31
|
+
|
32
|
+
# get ExtPubkey from priv_key
|
33
|
+
def ext_pubkey
|
34
|
+
k = ExtPubkey.new
|
35
|
+
k.depth = depth
|
36
|
+
k.number = number
|
37
|
+
k.parent_fingerprint = parent_fingerprint
|
38
|
+
k.chain_code = chain_code
|
39
|
+
k.pubkey = key.pubkey
|
40
|
+
k
|
41
|
+
end
|
42
|
+
|
43
|
+
# serialize extended private key
|
44
|
+
def to_payload
|
45
|
+
Bitcoin.chain_params.extended_privkey_version.htb << [depth].pack('C') <<
|
46
|
+
parent_fingerprint.htb << [number].pack('N') << chain_code << [0x00].pack('C') << key.priv_key.htb
|
47
|
+
end
|
48
|
+
|
49
|
+
# Base58 encoded extended private key
|
50
|
+
def to_base58
|
51
|
+
h = to_payload.bth
|
52
|
+
hex = h + Bitcoin.calc_checksum(h)
|
53
|
+
Base58.encode(hex)
|
54
|
+
end
|
55
|
+
|
56
|
+
# get private key(hex)
|
57
|
+
def priv
|
58
|
+
key.priv_key
|
59
|
+
end
|
60
|
+
|
61
|
+
# get public key(hex)
|
62
|
+
def pub
|
63
|
+
key.pubkey
|
64
|
+
end
|
65
|
+
|
66
|
+
# get address
|
67
|
+
def addr
|
68
|
+
key.to_p2pkh
|
69
|
+
end
|
70
|
+
|
71
|
+
# get segwit p2wpkh address
|
72
|
+
def segwit_addr
|
73
|
+
ext_pubkey.segwit_addr
|
74
|
+
end
|
75
|
+
|
76
|
+
# get key identifier
|
77
|
+
def identifier
|
78
|
+
Bitcoin.hash160(key.pubkey)
|
79
|
+
end
|
80
|
+
|
81
|
+
# get fingerprint
|
82
|
+
def fingerprint
|
83
|
+
identifier.slice(0..7)
|
84
|
+
end
|
85
|
+
|
86
|
+
# derive new key
|
87
|
+
def derive(number)
|
88
|
+
new_key = ExtKey.new
|
89
|
+
new_key.depth = depth + 1
|
90
|
+
new_key.number = number
|
91
|
+
new_key.parent_fingerprint = fingerprint
|
92
|
+
if number > (2**31 -1)
|
93
|
+
data = [0x00].pack('C') << key.priv_key.htb << [number].pack('N')
|
94
|
+
else
|
95
|
+
data = key.pubkey.htb << [number].pack('N')
|
96
|
+
end
|
97
|
+
l = Bitcoin.hmac_sha512(chain_code, data)
|
98
|
+
left = l[0..31].bth.to_i(16)
|
99
|
+
raise 'invalid key' if left >= CURVE_ORDER
|
100
|
+
child_priv = (left + key.priv_key.to_i(16)) % CURVE_ORDER
|
101
|
+
raise 'invalid key ' if child_priv >= CURVE_ORDER
|
102
|
+
new_key.key = Bitcoin::Key.new(priv_key: child_priv.to_s(16).rjust(64, '0'))
|
103
|
+
new_key.chain_code = l[32..-1]
|
104
|
+
new_key
|
105
|
+
end
|
106
|
+
|
107
|
+
# import private key from Base58 private key address
|
108
|
+
def self.from_base58(address)
|
109
|
+
data = StringIO.new(Base58.decode(address).htb)
|
110
|
+
ext_key = ExtKey.new
|
111
|
+
data.read(4).bth # version
|
112
|
+
ext_key.depth = data.read(1).unpack('C').first
|
113
|
+
ext_key.parent_fingerprint = data.read(4).bth
|
114
|
+
ext_key.number = data.read(4).unpack('N').first
|
115
|
+
ext_key.chain_code = data.read(32)
|
116
|
+
data.read(1) # 0x00
|
117
|
+
ext_key.key = Bitcoin::Key.new(priv_key: data.read(32).bth)
|
118
|
+
ext_key
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
# BIP-32 Extended public key
|
124
|
+
class ExtPubkey
|
125
|
+
attr_accessor :depth
|
126
|
+
attr_accessor :number
|
127
|
+
attr_accessor :chain_code
|
128
|
+
attr_accessor :pubkey # hex format
|
129
|
+
attr_accessor :parent_fingerprint
|
130
|
+
|
131
|
+
# serialize extended pubkey
|
132
|
+
def to_payload
|
133
|
+
Bitcoin.chain_params.extended_pubkey_version.htb << [depth].pack('C') <<
|
134
|
+
parent_fingerprint.htb << [number].pack('N') << chain_code << pub.htb
|
135
|
+
end
|
136
|
+
|
137
|
+
def pub
|
138
|
+
pubkey
|
139
|
+
end
|
140
|
+
|
141
|
+
# get address
|
142
|
+
def addr
|
143
|
+
Bitcoin::Key.new(pubkey: pubkey).to_p2pkh
|
144
|
+
end
|
145
|
+
|
146
|
+
# get segwit p2wpkh address
|
147
|
+
def segwit_addr
|
148
|
+
hash160 = Bitcoin.hash160(pub)
|
149
|
+
p2wpkh = [ ["00", "14", hash160].join ].pack("H*").bth
|
150
|
+
segwit_addr = Bech32::SegwitAddr.new
|
151
|
+
segwit_addr.hrp = Bitcoin.chain_params.address_version == '00' ? 'bc' : 'tb'
|
152
|
+
segwit_addr.script_pubkey = p2wpkh
|
153
|
+
segwit_addr.addr
|
154
|
+
end
|
155
|
+
|
156
|
+
# get key identifier
|
157
|
+
def identifier
|
158
|
+
Bitcoin.hash160(pub)
|
159
|
+
end
|
160
|
+
|
161
|
+
# get fingerprint
|
162
|
+
def fingerprint
|
163
|
+
identifier.slice(0..7)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Base58 encoded extended pubkey
|
167
|
+
def to_base58
|
168
|
+
h = to_payload.bth
|
169
|
+
hex = h + Bitcoin.calc_checksum(h)
|
170
|
+
Base58.encode(hex)
|
171
|
+
end
|
172
|
+
|
173
|
+
# derive child key
|
174
|
+
def derive(number)
|
175
|
+
new_key = ExtPubkey.new
|
176
|
+
new_key.depth = depth + 1
|
177
|
+
new_key.number = number
|
178
|
+
new_key.parent_fingerprint = fingerprint
|
179
|
+
raise 'hardened key is not support' if number > (2**31 -1)
|
180
|
+
data = pub.htb << [number].pack('N')
|
181
|
+
l = Bitcoin.hmac_sha512(chain_code, data)
|
182
|
+
left = l[0..31].bth.to_i(16)
|
183
|
+
raise 'invalid key' if left >= CURVE_ORDER
|
184
|
+
p1 = Bitcoin::Secp256k1::GROUP.generator.multiply_by_scalar(left)
|
185
|
+
p2 = Bitcoin::Key.new(pubkey: pubkey).to_point
|
186
|
+
new_key.pubkey = ECDSA::Format::PointOctetString.encode(p1 + p2, compression: true).bth
|
187
|
+
new_key.chain_code = l[32..-1]
|
188
|
+
new_key
|
189
|
+
end
|
190
|
+
|
191
|
+
# import pub key from Base58 private key address
|
192
|
+
def self.from_base58(address)
|
193
|
+
data = StringIO.new(Base58.decode(address).htb)
|
194
|
+
ext_pubkey = ExtPubkey.new
|
195
|
+
data.read(4).bth # version
|
196
|
+
ext_pubkey.depth = data.read(1).unpack('C').first
|
197
|
+
ext_pubkey.parent_fingerprint = data.read(4).bth
|
198
|
+
ext_pubkey.number = data.read(4).unpack('N').first
|
199
|
+
ext_pubkey.chain_code = data.read(32)
|
200
|
+
ext_pubkey.pubkey = data.read(33).bth
|
201
|
+
ext_pubkey
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|