bitcoinrb 0.2.2 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/
|
1
|
+
# Bitcoinrb [![Build Status](https://travis-ci.org/chaintope/bitcoinrb.svg?branch=master)](https://travis-ci.org/chaintope/bitcoinrb) [![Gem Version](https://badge.fury.io/rb/bitcoinrb.svg)](https://badge.fury.io/rb/bitcoinrb) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](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."
|