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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 524753cfa61041f101f72d76e914f70b20b504fb0eecad9d378a436afe7db718
4
- data.tar.gz: f3181a60120da9f892ceaaaaf22aba5923b26f495fb9fb9dd314c5cce8127129
3
+ metadata.gz: f552597dfd50a5df7cee6e6c29c10789afbbe5e78ad316af9833f25e99f15e76
4
+ data.tar.gz: 9044c1daafb7c4badee574cdd326a922354b64376b9b871da3b2f5ad6a8aa4e6
5
5
  SHA512:
6
- metadata.gz: da27669ddabc4d64bf3c96d4e83eb8c5d90ef837ed91b6f2e1d0e7d50c74153c62ff39eecb1867463f5a8435f7643d62ba6108e7a10d1fa46e4b10178fe8e2f1
7
- data.tar.gz: 2f85e04fecddba5bb1d1ce4fc61bf79fd972280f4834e56a4b56974958903e74bd1d19789c93d6bdebe8bead9b5fca8ad26d4c35967760cf0517da42ebfeb35d
6
+ metadata.gz: '09d270868f51f4a08af65dbedce68d87d1863bb8f82dbf32c8999eb40bad432910325d5d17efc7c8d23f2f0398614cca8d4852dd3a52bd232ab0576bb0e7ee61'
7
+ data.tar.gz: 0b958912e698973c4e1b4af4f9737a046b3d07566064bdd759ec7fa4c336a33861ec060a90f7bc9181c5a8a7f6fe91240359232ee0cefbcfc799580f59e861e5
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.0
1
+ 2.5.3
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.0
4
- - 2.4.1
5
- - 2.5.0
3
+ - 2.3.8
4
+ - 2.4.5
5
+ - 2.5.3
6
6
  addons:
7
7
  apt:
8
8
  packages:
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Bitcoinrb [![Build Status](https://travis-ci.org/haw-itn/bitcoinrb.svg?branch=master)](https://travis-ci.org/haw-itn/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">
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/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/mainnet.yml.
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/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/testnet.yml.
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/haw-itn/bitcoinrb/blob/master/lib/bitcoin/chainparams/regtest.yml.
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@haw.co.jp"]
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/haw-itn/bitcoinrb'
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
- private_key = ECDSA::Format::IntegerOctetString.decode(privkey.htb)
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
- attr_accessor :inventory
10
+ attr_reader :inventories
9
11
 
10
12
  COMMAND = 'notfound'
11
13
 
12
- def initialize(identifier, hash)
13
- @inventory = Inventory.new(identifier, hash)
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
@@ -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
- peer.id = allocate_peer_id
52
- unless peers.find(&:primary?)
53
- peer.primary = true
54
- peer.start_block_header_download
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, 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
- nonce = generate_rfc6979_nonce(data, privkey)
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
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -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
- derived_receive_keys.map(&:hash160) + derived_change_keys.map(&:hash160)
123
+ wallet.db.get_keys(self).map { |key| Bitcoin.hash160(key) }
115
124
  end
116
125
 
117
126
  def to_h
@@ -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.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-09-29 00:00:00.000000000 Z
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@haw.co.jp
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/haw-itn/bitcoinrb
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.3
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."