bitcoinrb 0.2.2 → 0.2.4
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 +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +3 -3
- data/README.md +4 -17
- data/bitcoinrb.gemspec +3 -2
- data/lib/bitcoin/key.rb +21 -4
- data/lib/bitcoin/message/not_found.rb +5 -13
- data/lib/bitcoin/network/pool.rb +9 -5
- data/lib/bitcoin/secp256k1/native.rb +5 -2
- data/lib/bitcoin/secp256k1/ruby.rb +9 -8
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +12 -3
- data/lib/bitcoin/wallet/db.rb +16 -0
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f552597dfd50a5df7cee6e6c29c10789afbbe5e78ad316af9833f25e99f15e76
|
4
|
+
data.tar.gz: 9044c1daafb7c4badee574cdd326a922354b64376b9b871da3b2f5ad6a8aa4e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09d270868f51f4a08af65dbedce68d87d1863bb8f82dbf32c8999eb40bad432910325d5d17efc7c8d23f2f0398614cca8d4852dd3a52bd232ab0576bb0e7ee61'
|
7
|
+
data.tar.gz: 0b958912e698973c4e1b4af4f9737a046b3d07566064bdd759ec7fa4c336a33861ec060a90f7bc9181c5a8a7f6fe91240359232ee0cefbcfc799580f59e861e5
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.5.
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Bitcoinrb [](https://travis-ci.org/chaintope/bitcoinrb) [](https://badge.fury.io/rb/bitcoinrb) [](LICENSE) <img src="http://segwit.co/static/public/images/logo.png" width="100">
|
2
2
|
|
3
3
|
|
4
4
|
Bitcoinrb is a Ruby implementation of Bitcoin Protocol.
|
@@ -68,7 +68,7 @@ The parameters of the blockchain are managed by `Bitcoin::ChainParams`. Switch c
|
|
68
68
|
Bitcoin.chain_params = :mainnet
|
69
69
|
```
|
70
70
|
|
71
|
-
This parameter is described in https://github.com/
|
71
|
+
This parameter is described in https://github.com/chaintope/bitcoinrb/blob/master/lib/bitcoin/chainparams/mainnet.yml.
|
72
72
|
|
73
73
|
* testnet
|
74
74
|
|
@@ -76,7 +76,7 @@ This parameter is described in https://github.com/haw-itn/bitcoinrb/blob/master/
|
|
76
76
|
Bitcoin.chain_params = :testnet
|
77
77
|
```
|
78
78
|
|
79
|
-
This parameter is described in https://github.com/
|
79
|
+
This parameter is described in https://github.com/chaintope/bitcoinrb/blob/master/lib/bitcoin/chainparams/testnet.yml.
|
80
80
|
|
81
81
|
* regtest
|
82
82
|
|
@@ -84,20 +84,7 @@ This parameter is described in https://github.com/haw-itn/bitcoinrb/blob/master/
|
|
84
84
|
Bitcoin.chain_params = :regtest
|
85
85
|
```
|
86
86
|
|
87
|
-
This parameter is described in https://github.com/
|
88
|
-
|
89
|
-
#### Fork coin
|
90
|
-
|
91
|
-
When using with fork coin, please specify the fork_id of the coin as follows.
|
92
|
-
|
93
|
-
```ruby
|
94
|
-
Bitcoin.chain_params.fork_id = 0 # 0 is bch fork id
|
95
|
-
```
|
96
|
-
|
97
|
-
Currently bitcoinrb supports only support and verification of transaction replay protection using `SIGHASH_FORK_ID`.
|
98
|
-
For details of `SIGHASH_FORK_ID`, refer to the following.
|
99
|
-
|
100
|
-
https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
|
87
|
+
This parameter is described in https://github.com/chaintope/bitcoinrb/blob/master/lib/bitcoin/chainparams/regtest.yml.
|
101
88
|
|
102
89
|
## Contributing
|
103
90
|
|
data/bitcoinrb.gemspec
CHANGED
@@ -8,11 +8,11 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.name = "bitcoinrb"
|
9
9
|
spec.version = Bitcoin::VERSION
|
10
10
|
spec.authors = ["azuchi"]
|
11
|
-
spec.email = ["azuchi@
|
11
|
+
spec.email = ["azuchi@chaintope.com"]
|
12
12
|
|
13
13
|
spec.summary = %q{[WIP]The implementation of Bitcoin Protocol for Ruby.}
|
14
14
|
spec.description = %q{[WIP]The implementation of Bitcoin Protocol for Ruby.}
|
15
|
-
spec.homepage = 'https://github.com/
|
15
|
+
spec.homepage = 'https://github.com/chaintope/bitcoinrb'
|
16
16
|
spec.license = "MIT"
|
17
17
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_runtime_dependency 'iniparse'
|
34
34
|
spec.add_runtime_dependency 'siphash'
|
35
35
|
spec.add_runtime_dependency 'protobuf'
|
36
|
+
spec.add_runtime_dependency 'scrypt'
|
36
37
|
|
37
38
|
# for options
|
38
39
|
spec.add_development_dependency 'leveldb-ruby'
|
data/lib/bitcoin/key.rb
CHANGED
@@ -87,9 +87,20 @@ module Bitcoin
|
|
87
87
|
|
88
88
|
# sign +data+ with private key
|
89
89
|
# @param [String] data a data to be signed with binary format
|
90
|
+
# @param [Boolean] low_r flag to apply low-R.
|
91
|
+
# @param [String] extra_entropy the extra entropy for rfc6979.
|
90
92
|
# @return [String] signature data with binary format
|
91
|
-
def sign(data)
|
92
|
-
secp256k1_module.sign_data(data, priv_key)
|
93
|
+
def sign(data, low_r = true, extra_entropy = nil)
|
94
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
95
|
+
if low_r && !sig_has_low_r?(sig)
|
96
|
+
counter = 1
|
97
|
+
until sig_has_low_r?(sig)
|
98
|
+
extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
|
99
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
100
|
+
counter += 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
sig
|
93
104
|
end
|
94
105
|
|
95
106
|
# verify signature using public key
|
@@ -242,8 +253,7 @@ module Bitcoin
|
|
242
253
|
# @param [Boolean] compressed pubkey compressed?
|
243
254
|
# @return [String] a pubkey which generate from privkey
|
244
255
|
def generate_pubkey(privkey, compressed: true)
|
245
|
-
|
246
|
-
public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(private_key)
|
256
|
+
public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16))
|
247
257
|
pubkey = ECDSA::Format::PointOctetString.encode(public_key, compression: compressed)
|
248
258
|
pubkey.bth
|
249
259
|
end
|
@@ -272,6 +282,13 @@ module Bitcoin
|
|
272
282
|
!pubkey.nil? && pubkey.size > 0
|
273
283
|
end
|
274
284
|
|
285
|
+
# check whether the signature is low-R
|
286
|
+
# @param [String] sig the signature data
|
287
|
+
# @return [Boolean] result
|
288
|
+
def sig_has_low_r?(sig)
|
289
|
+
sig[3].bth.to_i(16) == 0x20 && sig[4].bth.to_i(16) < 0x80
|
290
|
+
end
|
291
|
+
|
275
292
|
end
|
276
293
|
|
277
294
|
end
|
@@ -4,23 +4,15 @@ module Bitcoin
|
|
4
4
|
# notfound message
|
5
5
|
# https://bitcoin.org/en/developer-reference#notfound
|
6
6
|
class NotFound < Base
|
7
|
+
include InventoriesParser
|
8
|
+
extend InventoriesParser
|
7
9
|
|
8
|
-
|
10
|
+
attr_reader :inventories
|
9
11
|
|
10
12
|
COMMAND = 'notfound'
|
11
13
|
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.parse_from_payload(payload)
|
17
|
-
size, inventory_payload = Bitcoin.unpack_var_int(payload)
|
18
|
-
inventory = Inventory.parse_from_payload(inventory_payload)
|
19
|
-
new(inventory.identifier, inventory.hash)
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_payload
|
23
|
-
Bitcoin.pack_var_int(1) << inventory.to_payload
|
14
|
+
def initialize(inventories = [])
|
15
|
+
@inventories = inventories
|
24
16
|
end
|
25
17
|
|
26
18
|
end
|
data/lib/bitcoin/network/pool.rb
CHANGED
@@ -21,6 +21,7 @@ module Bitcoin
|
|
21
21
|
attr_reader :logger
|
22
22
|
attr_reader :peer_discovery
|
23
23
|
attr_accessor :started
|
24
|
+
attr_reader :mutex
|
24
25
|
|
25
26
|
def initialize(node, chain, configuration)
|
26
27
|
@node = node
|
@@ -32,6 +33,7 @@ module Bitcoin
|
|
32
33
|
@configuration = configuration
|
33
34
|
@peer_discovery = PeerDiscovery.new(configuration)
|
34
35
|
@started = false
|
36
|
+
@mutex = Mutex.new
|
35
37
|
end
|
36
38
|
|
37
39
|
# connecting other peers and begin network activity.
|
@@ -48,12 +50,14 @@ module Bitcoin
|
|
48
50
|
# detect new peer connection.
|
49
51
|
def handle_new_peer(peer)
|
50
52
|
logger.debug "connected new peer #{peer.addr}."
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
mutex.synchronize do
|
54
|
+
peer.id = allocate_peer_id
|
55
|
+
unless peers.find(&:primary?)
|
56
|
+
peer.primary = true
|
57
|
+
peer.start_block_header_download
|
58
|
+
end
|
59
|
+
peers << peer
|
55
60
|
end
|
56
|
-
peers << peer
|
57
61
|
pending_peers.delete(peer)
|
58
62
|
filter_load(peer) if node.wallet
|
59
63
|
end
|
@@ -107,20 +107,23 @@ module Bitcoin
|
|
107
107
|
# sign data.
|
108
108
|
# @param [String] data a data to be signed with binary format
|
109
109
|
# @param [String] privkey a private key using sign
|
110
|
+
# @param [String] extra_entropy a extra entropy for rfc6979
|
110
111
|
# @return [String] signature data with binary format
|
111
|
-
def sign_data(data, privkey)
|
112
|
+
def sign_data(data, privkey, extra_entropy)
|
112
113
|
with_context do |context|
|
113
114
|
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
114
115
|
raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
|
115
116
|
|
116
117
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
117
118
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
119
|
+
entropy = extra_entropy ? FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, extra_entropy) : nil
|
118
120
|
|
119
121
|
ret, tries, max = 0, 0, 20
|
122
|
+
|
120
123
|
while ret != 1
|
121
124
|
raise 'secp256k1_ecdsa_sign failed.' if tries >= max
|
122
125
|
tries += 1
|
123
|
-
ret = secp256k1_ecdsa_sign(context, internal_signature, msg32, secret, nil,
|
126
|
+
ret = secp256k1_ecdsa_sign(context, internal_signature, msg32, secret, nil, entropy)
|
124
127
|
end
|
125
128
|
|
126
129
|
signature = FFI::MemoryPointer.new(:uchar, 72)
|
@@ -26,10 +26,11 @@ module Bitcoin
|
|
26
26
|
# @param [String] data a data to be signed with binary format
|
27
27
|
# @param [String] privkey a private key using sign
|
28
28
|
# @return [String] signature data with binary format
|
29
|
-
def sign_data(data, privkey)
|
29
|
+
def sign_data(data, privkey, extra_entropy)
|
30
30
|
privkey = privkey.htb
|
31
31
|
private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
|
32
|
-
|
32
|
+
extra_entropy ||= ''
|
33
|
+
nonce = generate_rfc6979_nonce(data, privkey, extra_entropy)
|
33
34
|
|
34
35
|
# port form ecdsa gem.
|
35
36
|
r_point = GROUP.new_point(nonce)
|
@@ -83,15 +84,15 @@ module Bitcoin
|
|
83
84
|
|
84
85
|
# generate temporary key k to be used when ECDSA sign.
|
85
86
|
# https://tools.ietf.org/html/rfc6979#section-3.2
|
86
|
-
def generate_rfc6979_nonce(data, privkey)
|
87
|
-
v = ('01' * 32).htb
|
88
|
-
k = ('00' * 32).htb
|
87
|
+
def generate_rfc6979_nonce(data, privkey, extra_entropy)
|
88
|
+
v = ('01' * 32).htb # 3.2.b
|
89
|
+
k = ('00' * 32).htb # 3.2.c
|
89
90
|
# 3.2.d
|
90
|
-
k = Bitcoin.hmac_sha256(k, v + '00'.htb + privkey + data)
|
91
|
+
k = Bitcoin.hmac_sha256(k, v + '00'.htb + privkey + data + extra_entropy)
|
91
92
|
# 3.2.e
|
92
93
|
v = Bitcoin.hmac_sha256(k, v)
|
93
94
|
# 3.2.f
|
94
|
-
k = Bitcoin.hmac_sha256(k, v + '01'.htb + privkey + data)
|
95
|
+
k = Bitcoin.hmac_sha256(k, v + '01'.htb + privkey + data + extra_entropy)
|
95
96
|
# 3.2.g
|
96
97
|
v = Bitcoin.hmac_sha256(k, v)
|
97
98
|
# 3.2.h
|
@@ -102,7 +103,7 @@ module Bitcoin
|
|
102
103
|
t_num = t.bth.to_i(16)
|
103
104
|
return t_num if 1 <= t_num && t_num < GROUP.order
|
104
105
|
k = Bitcoin.hmac_sha256(k, v + '00'.htb)
|
105
|
-
v = Bitcoin.hmac_sha256(v)
|
106
|
+
v = Bitcoin.hmac_sha256(k, v)
|
106
107
|
end
|
107
108
|
raise 'A valid nonce was not found.'
|
108
109
|
end
|
data/lib/bitcoin/version.rb
CHANGED
@@ -57,7 +57,7 @@ module Bitcoin
|
|
57
57
|
def create_receive
|
58
58
|
@receive_depth += 1
|
59
59
|
save
|
60
|
-
derive_key(0, @receive_depth)
|
60
|
+
save_key(0, @receive_depth, derive_key(0, @receive_depth))
|
61
61
|
end
|
62
62
|
|
63
63
|
# create new change key
|
@@ -65,12 +65,21 @@ module Bitcoin
|
|
65
65
|
def create_change
|
66
66
|
@change_depth += 1
|
67
67
|
save
|
68
|
-
derive_key(1, @change_depth)
|
68
|
+
save_key(1, @change_depth, derive_key(1, @change_depth))
|
69
69
|
end
|
70
70
|
|
71
71
|
# save this account payload to database.
|
72
72
|
def save
|
73
73
|
wallet.db.save_account(self)
|
74
|
+
save_key(0, receive_depth, derive_key(0, receive_depth)) if receive_depth.zero?
|
75
|
+
save_key(1, change_depth, derive_key(1, change_depth)) if change_depth.zero?
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param purpose 0:recieve, 1:change
|
79
|
+
# @param index receive_depth or change_depth
|
80
|
+
# @param key the key to be saved
|
81
|
+
def save_key(purpose, index, key)
|
82
|
+
wallet.db.save_key(self, purpose, index, key)
|
74
83
|
end
|
75
84
|
|
76
85
|
# get the list of derived keys for receive key.
|
@@ -111,7 +120,7 @@ module Bitcoin
|
|
111
120
|
# get data elements tobe monitored with Bloom Filter.
|
112
121
|
# @return [Array[String]]
|
113
122
|
def watch_targets
|
114
|
-
|
123
|
+
wallet.db.get_keys(self).map { |key| Bitcoin.hash160(key) }
|
115
124
|
end
|
116
125
|
|
117
126
|
def to_h
|
data/lib/bitcoin/wallet/db.rb
CHANGED
@@ -7,6 +7,7 @@ module Bitcoin
|
|
7
7
|
account: 'a', # key: account index, value: Account raw data.
|
8
8
|
master: 'm', # value: wallet seed.
|
9
9
|
version: 'v', # value: wallet version
|
10
|
+
key: 'k', # key: path to the key, value: public key
|
10
11
|
}
|
11
12
|
|
12
13
|
attr_reader :level_db
|
@@ -37,6 +38,21 @@ module Bitcoin
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def save_key(account, purpose, index, key)
|
42
|
+
pubkey = key.pub
|
43
|
+
id = [account.purpose, account.index, purpose, index].pack('I*').bth
|
44
|
+
k = KEY_PREFIX[:key] + id
|
45
|
+
level_db.put(k, pubkey)
|
46
|
+
key
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_keys(account)
|
50
|
+
id = [account.purpose, account.index].pack('I*').bth
|
51
|
+
from = KEY_PREFIX[:key] + id + '00000000'
|
52
|
+
to = KEY_PREFIX[:key] + id + 'ffffffff'
|
53
|
+
level_db.each(from: from, to: to).map { |k, v| v}
|
54
|
+
end
|
55
|
+
|
40
56
|
# get master_key
|
41
57
|
def master_key
|
42
58
|
@master_key ||= Bitcoin::Wallet::MasterKey.parse_from_payload(level_db.get(KEY_PREFIX[:master]))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitcoinrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: scrypt
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
name: leveldb-ruby
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -264,7 +278,7 @@ dependencies:
|
|
264
278
|
version: '0'
|
265
279
|
description: "[WIP]The implementation of Bitcoin Protocol for Ruby."
|
266
280
|
email:
|
267
|
-
- azuchi@
|
281
|
+
- azuchi@chaintope.com
|
268
282
|
executables:
|
269
283
|
- bitcoinrb-cli
|
270
284
|
- bitcoinrbd
|
@@ -403,7 +417,7 @@ files:
|
|
403
417
|
- lib/openassets/marker_output.rb
|
404
418
|
- lib/openassets/payload.rb
|
405
419
|
- lib/openassets/util.rb
|
406
|
-
homepage: https://github.com/
|
420
|
+
homepage: https://github.com/chaintope/bitcoinrb
|
407
421
|
licenses:
|
408
422
|
- MIT
|
409
423
|
metadata: {}
|
@@ -423,7 +437,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
423
437
|
version: '0'
|
424
438
|
requirements: []
|
425
439
|
rubyforge_project:
|
426
|
-
rubygems_version: 2.7.
|
440
|
+
rubygems_version: 2.7.8
|
427
441
|
signing_key:
|
428
442
|
specification_version: 4
|
429
443
|
summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."
|