money-tree 0.8.9 → 0.9.0

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
  SHA1:
3
- metadata.gz: d626fc55825195bcbd6c57406598ed66ed9ebeaf
4
- data.tar.gz: b1e82a84328bf2fcf4366ccf7995a156f5a09b43
3
+ metadata.gz: b30fcb1b0feac18dde7d94b62a0ff97666209d3f
4
+ data.tar.gz: ffa45ca51da46d1d56d701f24e36d61848e261ea
5
5
  SHA512:
6
- metadata.gz: 56e979b90b695673384164ef2c371160ae8d9988b7c9f7b4dcc4f0822c1619fbee7b0c0698605f3edd5fde8cd7f09f88233e83477e6537bb1e50ae60f19d9f22
7
- data.tar.gz: 04d26f09a34e7b51cd4f42ff33b7b942a19b4d710f07738b29d5e60c02086e2f4d7ea271139a665f1195ef4bce8ce9264da4cc715bdb2dfcfc8c16903a4e1e09
6
+ metadata.gz: 859a1b5a4dfd21fafb73dba60ad6d243c3d8462bba900aed584934e463976fd0075abd5fa83b6317f54ce9801f342e3ba31ac639bb53ee9769068fd1f1cbda13
7
+ data.tar.gz: 3609f386e6fc5276f41a51221898dc0ebb10d314fd4b76a6ea4522ced950738b064167fb0f4d6a7d84c1b12823dd255494043e817b9dd7562f3f3eb4c02e093d
Binary file
Binary file
@@ -8,8 +8,8 @@ module MoneyTree
8
8
  @public_key = MoneyTree::PublicKey.new(@private_key, opts)
9
9
  end
10
10
 
11
- def to_s
12
- public_key.to_s
11
+ def to_s(network: :bitcoin)
12
+ public_key.to_s(network: network)
13
13
  end
14
14
 
15
15
  end
@@ -13,10 +13,10 @@ module MoneyTree
13
13
  class KeyFormatNotFound < Exception; end
14
14
  class InvalidWIFFormat < Exception; end
15
15
  class InvalidBase64Format < Exception; end
16
-
17
- attr_reader :options, :key, :raw_key, :network, :network_key
16
+
17
+ attr_reader :options, :key, :raw_key
18
18
  attr_accessor :ec_key
19
-
19
+
20
20
  GROUP_NAME = 'secp256k1'
21
21
  ORDER = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".to_i(16)
22
22
 
@@ -24,23 +24,21 @@ module MoneyTree
24
24
  eckey ||= ec_key
25
25
  eckey.nil? ? false : eckey.check_key
26
26
  end
27
-
27
+
28
28
  def to_bytes
29
29
  hex_to_bytes to_hex
30
30
  end
31
-
31
+
32
32
  def to_i
33
33
  bytes_to_int to_bytes
34
34
  end
35
35
  end
36
-
36
+
37
37
  class PrivateKey < Key
38
-
38
+
39
39
  def initialize(opts = {})
40
40
  @options = opts
41
41
  @ec_key = PKey::EC.new GROUP_NAME
42
- @network_key = options[:network] || :bitcoin
43
- @network = MoneyTree::NETWORKS[network_key]
44
42
  if @options[:key]
45
43
  @raw_key = @options[:key]
46
44
  @key = parse_raw_key
@@ -50,34 +48,34 @@ module MoneyTree
50
48
  @key = to_hex
51
49
  end
52
50
  end
53
-
51
+
54
52
  def generate
55
53
  ec_key.generate_key
56
54
  end
57
-
55
+
58
56
  def import
59
57
  ec_key.private_key = BN.new(key, 16)
60
58
  set_public_key
61
59
  end
62
-
60
+
63
61
  def calculate_public_key(opts = {})
64
62
  opts[:compressed] = true unless opts[:compressed] == false
65
63
  group = ec_key.group
66
64
  group.point_conversion_form = opts[:compressed] ? :compressed : :uncompressed
67
65
  point = group.generator.mul ec_key.private_key
68
66
  end
69
-
67
+
70
68
  def set_public_key(opts = {})
71
69
  ec_key.public_key = calculate_public_key(opts)
72
70
  end
73
-
71
+
74
72
  def parse_raw_key
75
73
  result = if raw_key.is_a?(Bignum) then from_bignum
76
74
  elsif hex_format? then from_hex
77
75
  elsif base64_format? then from_base64
78
76
  elsif compressed_wif_format? then from_wif
79
77
  elsif uncompressed_wif_format? then from_wif
80
- else
78
+ else
81
79
  raise KeyFormatNotFound
82
80
  end
83
81
  result.downcase
@@ -91,25 +89,15 @@ module MoneyTree
91
89
  def from_hex(hex = raw_key)
92
90
  hex
93
91
  end
94
-
92
+
95
93
  def from_wif(wif = raw_key)
96
94
  compressed = wif.length == 52
97
- parse_network_from_wif(wif, compressed: compressed)
98
95
  validate_wif(wif)
99
96
  hex = decode_base58(wif)
100
97
  last_char = compressed ? -11 : -9
101
98
  hex.slice(2..last_char)
102
99
  end
103
100
 
104
- def parse_network_from_wif(wif, opts = {})
105
- networks = MoneyTree::NETWORKS
106
- chars_key = opts[:compressed] ? :compressed_wif_chars : :uncompressed_wif_chars
107
- @network_key = networks.keys.select do |k|
108
- networks[k][chars_key].include?(wif.slice(0))
109
- end.first
110
- @network = networks[network_key]
111
- end
112
-
113
101
  def from_base64(base64_key = raw_key)
114
102
  raise InvalidBase64Format unless base64_format?(base64_key)
115
103
  decode_base64(base64_key)
@@ -118,7 +106,7 @@ module MoneyTree
118
106
  def compressed_wif_format?
119
107
  wif_format?(:compressed)
120
108
  end
121
-
109
+
122
110
  def uncompressed_wif_format?
123
111
  wif_format?(:uncompressed)
124
112
  end
@@ -132,19 +120,18 @@ module MoneyTree
132
120
  def base64_format?(base64_key = raw_key)
133
121
  base64_key.length == 44 && base64_key =~ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
134
122
  end
135
-
123
+
136
124
  def hex_format?
137
125
  raw_key.length == 64 && !raw_key[/\H/]
138
126
  end
139
-
127
+
140
128
  def to_hex
141
129
  int_to_hex @ec_key.private_key, 64
142
130
  end
143
-
144
- def to_wif(opts = {})
145
- opts[:compressed] = true unless opts[:compressed] == false
146
- source = network[:privkey_version] + to_hex
147
- source += network[:privkey_compression_flag] if opts[:compressed]
131
+
132
+ def to_wif(compressed: true, network: :bitcoin)
133
+ source = NETWORKS[network][:privkey_version] + to_hex
134
+ source += NETWORKS[network][:privkey_compression_flag] if compressed
148
135
  hash = sha256(source)
149
136
  hash = sha256(hash)
150
137
  checksum = hash.slice(0..7)
@@ -154,7 +141,6 @@ module MoneyTree
154
141
 
155
142
  def wif_valid?(wif)
156
143
  hex = decode_base58(wif)
157
- return false unless hex.slice(0..1) == network[:privkey_version]
158
144
  checksum = hex.chars.to_a.pop(8).join
159
145
  source = hex.slice(0..-9)
160
146
  hash = sha256(source)
@@ -162,68 +148,61 @@ module MoneyTree
162
148
  hash_checksum = hash.slice(0..7)
163
149
  checksum == hash_checksum
164
150
  end
165
-
151
+
166
152
  def validate_wif(wif)
167
153
  raise InvalidWIFFormat unless wif_valid?(wif)
168
154
  end
169
-
155
+
170
156
  def to_base64
171
157
  encode_base64(to_hex)
172
158
  end
173
-
174
- def to_s
175
- to_wif
159
+
160
+ def to_s(network: :bitcoin)
161
+ to_wif(network: network)
176
162
  end
177
-
163
+
178
164
  end
179
-
165
+
180
166
  class PublicKey < Key
181
167
  attr_reader :private_key, :point, :group, :key_int
182
-
168
+
183
169
  def initialize(p_key, opts = {})
184
170
  @options = opts
185
171
  @options[:compressed] = true if @options[:compressed].nil?
186
-
187
172
  if p_key.is_a?(PrivateKey)
188
173
  @private_key = p_key
189
- @network_key = private_key.network_key
190
- @network = MoneyTree::NETWORKS[network_key]
191
174
  @point = @private_key.calculate_public_key(@options)
192
175
  @group = @point.group
193
176
  @key = @raw_key = to_hex
194
177
  else
195
- @network_key = @options[:network] || :bitcoin
196
- @network = MoneyTree::NETWORKS[network_key]
197
178
  @raw_key = p_key
198
179
  @group = PKey::EC::Group.new GROUP_NAME
199
180
  @key = parse_raw_key
200
181
  end
201
182
 
202
- @options[:network] = @network_key # remember for deep clone
203
-
204
183
  raise ArgumentError, "Must initialize with a MoneyTree::PrivateKey or a public key value" if @key.nil?
205
184
  end
206
-
185
+
207
186
  def compression
208
187
  @group.point_conversion_form
209
188
  end
210
-
189
+
211
190
  def compression=(compression_type = :compressed)
212
191
  @group.point_conversion_form = compression_type
213
192
  end
214
-
193
+
215
194
  def compressed
216
195
  compressed_key = self.class.new raw_key, options # deep clone
217
196
  compressed_key.set_point to_i, compressed: true
218
197
  compressed_key
219
198
  end
220
-
199
+
221
200
  def uncompressed
222
201
  uncompressed_key = self.class.new raw_key, options # deep clone
223
202
  uncompressed_key.set_point to_i, compressed: false
224
203
  uncompressed_key
225
204
  end
226
-
205
+
227
206
  def set_point(int = to_i, opts = {})
228
207
  opts = options.merge(opts)
229
208
  opts[:compressed] = true if opts[:compressed].nil?
@@ -232,7 +211,7 @@ module MoneyTree
232
211
  @point = PKey::EC::Point.new group, bn
233
212
  raise KeyInvalid, 'point is not on the curve' unless @point.on_curve?
234
213
  end
235
-
214
+
236
215
  def parse_raw_key
237
216
  result = if raw_key.is_a?(Bignum)
238
217
  set_point raw_key
@@ -240,45 +219,45 @@ module MoneyTree
240
219
  set_point hex_to_int(raw_key), compressed: false
241
220
  elsif compressed_hex_format?
242
221
  set_point hex_to_int(raw_key), compressed: true
243
- else
222
+ else
244
223
  raise KeyFormatNotFound
245
224
  end
246
225
  to_hex
247
226
  end
248
-
227
+
249
228
  def hex_format?
250
229
  raw_key.length == 130 && !raw_key[/\H/]
251
230
  end
252
-
231
+
253
232
  def compressed_hex_format?
254
233
  raw_key.length == 66 && !raw_key[/\H/]
255
234
  end
256
-
235
+
257
236
  def to_hex
258
237
  int_to_hex to_i, 66
259
238
  end
260
-
239
+
261
240
  def to_i
262
241
  point.to_bn.to_i
263
242
  end
264
-
243
+
265
244
  def to_ripemd160
266
245
  hash = sha256 to_hex
267
246
  ripemd160 hash
268
247
  end
269
-
270
- def to_address
248
+
249
+ def to_address(network: :bitcoin)
271
250
  hash = to_ripemd160
272
- address = network[:address_version] + hash
251
+ address = NETWORKS[network][:address_version] + hash
273
252
  to_serialized_base58 address
274
253
  end
275
254
  alias :to_s :to_address
276
-
255
+
277
256
  def to_fingerprint
278
257
  hash = to_ripemd160
279
258
  hash.slice(0..7)
280
259
  end
281
-
260
+
282
261
  def to_bytes
283
262
  int_to_bytes to_i
284
263
  end
@@ -1,28 +1,35 @@
1
1
  module MoneyTree
2
- NETWORKS = {
3
- bitcoin: {
4
- address_version: '00',
5
- p2sh_version: '05',
6
- p2sh_char: '3',
7
- privkey_version: '80',
8
- privkey_compression_flag: '01',
9
- extended_privkey_version: "0488ade4",
10
- extended_pubkey_version: "0488b21e",
11
- compressed_wif_chars: %w(K L),
12
- uncompressed_wif_chars: %w(5),
13
- protocol_version: 70001
14
- },
15
- bitcoin_testnet: {
16
- address_version: '6f',
17
- p2sh_version: 'c4',
18
- p2sh_char: '2',
19
- privkey_version: 'ef',
20
- privkey_compression_flag: '01',
21
- extended_privkey_version: "04358394",
22
- extended_pubkey_version: "043587cf",
23
- compressed_wif_chars: %w(c),
24
- uncompressed_wif_chars: %w(9),
25
- protocol_version: 70001
26
- }
27
- }
2
+ NETWORKS =
3
+ begin
4
+ hsh = Hash.new do |_, key|
5
+ raise "#{key} is not a valid network!"
6
+ end.merge(
7
+ bitcoin: {
8
+ address_version: '00',
9
+ p2sh_version: '05',
10
+ p2sh_char: '3',
11
+ privkey_version: '80',
12
+ privkey_compression_flag: '01',
13
+ extended_privkey_version: "0488ade4",
14
+ extended_pubkey_version: "0488b21e",
15
+ compressed_wif_chars: %w(K L),
16
+ uncompressed_wif_chars: %w(5),
17
+ protocol_version: 70001
18
+ },
19
+ bitcoin_testnet: {
20
+ address_version: '6f',
21
+ p2sh_version: 'c4',
22
+ p2sh_char: '2',
23
+ privkey_version: 'ef',
24
+ privkey_compression_flag: '01',
25
+ extended_privkey_version: "04358394",
26
+ extended_pubkey_version: "043587cf",
27
+ compressed_wif_chars: %w(c),
28
+ uncompressed_wif_chars: %w(9),
29
+ protocol_version: 70001
30
+ }
31
+ )
32
+ hsh[:testnet3] = hsh[:bitcoin_testnet]
33
+ hsh
34
+ end
28
35
  end
@@ -2,62 +2,52 @@ module MoneyTree
2
2
  class Node
3
3
  include Support
4
4
  extend Support
5
- attr_reader :private_key, :public_key, :chain_code,
6
- :is_private, :depth, :index, :parent, :network, :network_key
7
-
5
+ attr_reader :private_key, :public_key, :chain_code,
6
+ :is_private, :depth, :index, :parent
7
+
8
8
  class PublicDerivationFailure < Exception; end
9
9
  class InvalidKeyForIndex < Exception; end
10
10
  class ImportError < Exception; end
11
11
  class PrivatePublicMismatch < Exception; end
12
-
12
+
13
13
  def initialize(opts = {})
14
- @network_key = opts.delete(:network) || :bitcoin
15
- @network = MoneyTree::NETWORKS[network_key]
16
14
  opts.each { |k, v| instance_variable_set "@#{k}", v }
17
15
  end
18
-
19
- def self.from_serialized_address(address)
16
+
17
+ def self.from_bip32(address, has_version: true)
20
18
  hex = from_serialized_base58 address
21
- version = from_version_hex hex.slice!(0..7)
19
+ hex.slice!(0..7) if has_version
22
20
  self.new({
23
21
  depth: hex.slice!(0..1).to_i(16),
24
22
  parent_fingerprint: hex.slice!(0..7),
25
23
  index: hex.slice!(0..7).to_i(16),
26
24
  chain_code: hex.slice!(0..63).to_i(16)
27
- }.merge(key_options(hex, version)))
28
- end
29
-
30
- def self.key_options(hex, version)
31
- k_opts = { network: version[:network] }
32
- if version[:private_key] && hex.slice(0..1) == '00'
33
- private_key = MoneyTree::PrivateKey.new({ key: hex.slice(2..-1) }.merge(k_opts))
34
- k_opts.merge private_key: private_key, public_key: MoneyTree::PublicKey.new(private_key)
25
+ }.merge(parse_out_key(hex)))
26
+ end
27
+
28
+ def self.from_serialized_address(address)
29
+ puts 'Node.from_serialized_address is DEPRECATED. Please use .from_bip32 instead.'
30
+ from_bip32(address)
31
+ end
32
+
33
+ def self.parse_out_key(hex)
34
+ if hex.slice(0..1) == '00'
35
+ private_key = MoneyTree::PrivateKey.new(key: hex.slice(2..-1))
36
+ {
37
+ private_key: private_key,
38
+ public_key: MoneyTree::PublicKey.new(private_key)
39
+ }
35
40
  elsif %w(02 03).include? hex.slice(0..1)
36
- k_opts.merge public_key: MoneyTree::PublicKey.new(hex, k_opts)
41
+ { public_key: MoneyTree::PublicKey.new(hex) }
37
42
  else
38
43
  raise ImportError, 'Public or private key data does not match version type'
39
44
  end
40
45
  end
41
-
42
- def self.from_version_hex(hex)
43
- case hex
44
- when MoneyTree::NETWORKS[:bitcoin][:extended_privkey_version]
45
- { private_key: true, network: :bitcoin }
46
- when MoneyTree::NETWORKS[:bitcoin][:extended_pubkey_version]
47
- { private_key: false, network: :bitcoin }
48
- when MoneyTree::NETWORKS[:bitcoin_testnet][:extended_privkey_version]
49
- { private_key: true, network: :bitcoin_testnet }
50
- when MoneyTree::NETWORKS[:bitcoin_testnet][:extended_pubkey_version]
51
- { private_key: false, network: :bitcoin_testnet }
52
- else
53
- raise ImportError, 'invalid version bytes'
54
- end
55
- end
56
-
46
+
57
47
  def is_private?
58
48
  index >= 0x80000000 || index < 0
59
49
  end
60
-
50
+
61
51
  def index_hex(i = index)
62
52
  if i < 0
63
53
  [i].pack('l>').unpack('H*').first
@@ -65,15 +55,15 @@ module MoneyTree
65
55
  i.to_s(16).rjust(8, "0")
66
56
  end
67
57
  end
68
-
58
+
69
59
  def depth_hex(depth)
70
60
  depth.to_s(16).rjust(2, "0")
71
61
  end
72
-
62
+
73
63
  def private_derivation_message(i)
74
64
  "\x00" + private_key.to_bytes + i_as_bytes(i)
75
65
  end
76
-
66
+
77
67
  def public_derivation_message(i)
78
68
  public_key.to_bytes << i_as_bytes(i)
79
69
  end
@@ -81,7 +71,7 @@ module MoneyTree
81
71
  def i_as_bytes(i)
82
72
  [i].pack('N')
83
73
  end
84
-
74
+
85
75
  def derive_private_key(i = 0)
86
76
  message = i >= 0x80000000 || i < 0 ? private_derivation_message(i) : public_derivation_message(i)
87
77
  hash = hmac_sha512 hex_to_bytes(chain_code_hex), message
@@ -92,7 +82,7 @@ module MoneyTree
92
82
  child_chain_code = right_from_hash(hash)
93
83
  return child_private_key, child_chain_code
94
84
  end
95
-
85
+
96
86
  def derive_public_key(i = 0)
97
87
  raise PrivatePublicMismatch if i >= 0x80000000
98
88
  message = public_derivation_message(i)
@@ -105,40 +95,45 @@ module MoneyTree
105
95
  child_chain_code = right_from_hash(hash)
106
96
  return child_public_key, child_chain_code
107
97
  end
108
-
98
+
109
99
  def left_from_hash(hash)
110
100
  bytes_to_int hash.bytes.to_a[0..31]
111
101
  end
112
-
102
+
113
103
  def right_from_hash(hash)
114
104
  bytes_to_int hash.bytes.to_a[32..-1]
115
105
  end
116
106
 
117
- def to_serialized_hex(type = :public)
107
+ def to_serialized_hex(type = :public, network: :bitcoin)
118
108
  raise PrivatePublicMismatch if type.to_sym == :private && private_key.nil?
119
109
  version_key = type.to_sym == :private ? :extended_privkey_version : :extended_pubkey_version
120
- hex = network[version_key] # version (4 bytes)
110
+ hex = NETWORKS[network][version_key] # version (4 bytes)
121
111
  hex += depth_hex(depth) # depth (1 byte)
122
112
  hex += parent_fingerprint # fingerprint of key (4 bytes)
123
113
  hex += index_hex(index) # child number i (4 bytes)
124
114
  hex += chain_code_hex
125
115
  hex += type.to_sym == :private ? "00#{private_key.to_hex}" : public_key.compressed.to_hex
126
116
  end
127
-
128
- def to_serialized_address(type = :public)
117
+
118
+ def to_bip32(type = :public, network: :bitcoin)
129
119
  raise PrivatePublicMismatch if type.to_sym == :private && private_key.nil?
130
- to_serialized_base58 to_serialized_hex(type)
120
+ to_serialized_base58 to_serialized_hex(type, network: network)
121
+ end
122
+
123
+ def to_serialized_address(type = :public, network: :bitcoin)
124
+ puts 'Node.to_serialized_address is DEPRECATED. Please use .to_bip32.'
125
+ to_bip32(type, network: network)
131
126
  end
132
127
 
133
128
  def to_identifier(compressed=true)
134
129
  key = compressed ? public_key.compressed : public_key.uncompressed
135
130
  key.to_ripemd160
136
131
  end
137
-
132
+
138
133
  def to_fingerprint
139
134
  public_key.compressed.to_fingerprint
140
135
  end
141
-
136
+
142
137
  def parent_fingerprint
143
138
  if @parent_fingerprint
144
139
  @parent_fingerprint
@@ -147,40 +142,39 @@ module MoneyTree
147
142
  end
148
143
  end
149
144
 
150
- def to_address(compressed=true)
151
- address = network[:address_version] + to_identifier(compressed)
145
+ def to_address(compressed=true, network: :bitcoin)
146
+ address = NETWORKS[network][:address_version] + to_identifier(compressed)
152
147
  to_serialized_base58 address
153
148
  end
154
-
149
+
155
150
  def subnode(i = 0, opts = {})
156
151
  if private_key.nil?
157
152
  child_public_key, child_chain_code = derive_public_key(i)
158
- child_public_key = MoneyTree::PublicKey.new child_public_key, network: network_key
153
+ child_public_key = MoneyTree::PublicKey.new child_public_key
159
154
  else
160
155
  child_private_key, child_chain_code = derive_private_key(i)
161
- child_private_key = MoneyTree::PrivateKey.new key: child_private_key, network: network_key
156
+ child_private_key = MoneyTree::PrivateKey.new key: child_private_key
162
157
  child_public_key = MoneyTree::PublicKey.new child_private_key
163
158
  end
164
-
165
- MoneyTree::Node.new network: network_key,
166
- depth: depth+1,
167
- index: i,
159
+
160
+ MoneyTree::Node.new( depth: depth+1,
161
+ index: i,
168
162
  private_key: private_key.nil? ? nil : child_private_key,
169
163
  public_key: child_public_key,
170
164
  chain_code: child_chain_code,
171
- parent: self
165
+ parent: self)
172
166
  end
173
-
167
+
174
168
  # path: a path of subkeys denoted by numbers and slashes. Use
175
169
  # p or i<0 for private key derivation. End with .pub to force
176
170
  # the key public.
177
- #
171
+ #
178
172
  # Examples:
179
173
  # 1p/-5/2/1 would call subkey(i=1, is_prime=True).subkey(i=-5).
180
174
  # subkey(i=2).subkey(i=1) and then yield the private key
181
175
  # 0/0/458.pub would call subkey(i=0).subkey(i=0).subkey(i=458) and
182
176
  # then yield the public key
183
- #
177
+ #
184
178
  # You should choose either the p or the negative number convention for private key derivation.
185
179
  def node_for_path(path)
186
180
  force_public = path[-4..-1] == '.pub'
@@ -204,11 +198,11 @@ module MoneyTree
204
198
  nodes.last
205
199
  end
206
200
  end
207
-
201
+
208
202
  def parse_index(path_part)
209
203
  is_prime = %w(p ').include? path_part[-1]
210
204
  i = path_part.to_i
211
-
205
+
212
206
  i = if i < 0
213
207
  i
214
208
  elsif is_prime
@@ -217,16 +211,16 @@ module MoneyTree
217
211
  i & 0x7fffffff
218
212
  end
219
213
  end
220
-
214
+
221
215
  def strip_private_info!
222
216
  @private_key = nil
223
217
  end
224
-
218
+
225
219
  def chain_code_hex
226
220
  int_to_hex chain_code, 64
227
221
  end
228
222
  end
229
-
223
+
230
224
  class Master < Node
231
225
  module SeedGeneration
232
226
  class Failure < Exception; end
@@ -236,18 +230,16 @@ module MoneyTree
236
230
  class ImportError < Failure; end
237
231
  class TooManyAttempts < Failure; end
238
232
  end
239
-
233
+
240
234
  HD_WALLET_BASE_KEY = "Bitcoin seed"
241
235
  RANDOM_SEED_SIZE = 32
242
-
236
+
243
237
  attr_reader :seed, :seed_hash
244
-
238
+
245
239
  def initialize(opts = {})
246
240
  @depth = 0
247
241
  @index = 0
248
242
  opts[:seed] = [opts[:seed_hex]].pack("H*") if opts[:seed_hex]
249
- @network_key = opts[:network] || :bitcoin
250
- @network = MoneyTree::NETWORKS[network_key]
251
243
  if opts[:seed]
252
244
  @seed = opts[:seed]
253
245
  @seed_hash = generate_seed_hash(@seed)
@@ -258,14 +250,12 @@ module MoneyTree
258
250
  @chain_code = opts[:chain_code]
259
251
  if opts[:private_key]
260
252
  @private_key = opts[:private_key]
261
- @network_key = @private_key.network_key
262
- @network = MoneyTree::NETWORKS[network_key]
263
253
  @public_key = MoneyTree::PublicKey.new @private_key
264
254
  else opts[:public_key]
265
255
  @public_key = if opts[:public_key].is_a?(MoneyTree::PublicKey)
266
256
  opts[:public_key]
267
257
  else
268
- MoneyTree::PublicKey.new(opts[:public_key], network: network_key)
258
+ MoneyTree::PublicKey.new(opts[:public_key])
269
259
  end
270
260
  end
271
261
  else
@@ -273,29 +263,29 @@ module MoneyTree
273
263
  set_seeded_keys
274
264
  end
275
265
  end
276
-
266
+
277
267
  def is_private?
278
268
  true
279
269
  end
280
-
270
+
281
271
  def generate_seed
282
272
  @seed = OpenSSL::Random.random_bytes(32)
283
273
  @seed_hash = generate_seed_hash(@seed)
284
274
  raise SeedGeneration::ValidityError unless seed_valid?(@seed_hash)
285
275
  end
286
-
276
+
287
277
  def generate_seed_hash(seed)
288
278
  hmac_sha512 HD_WALLET_BASE_KEY, seed
289
279
  end
290
-
280
+
291
281
  def seed_valid?(seed_hash)
292
282
  return false unless seed_hash.bytesize == 64
293
283
  master_key = left_from_hash(seed_hash)
294
284
  !master_key.zero? && master_key < MoneyTree::Key::ORDER
295
285
  end
296
-
286
+
297
287
  def set_seeded_keys
298
- @private_key = MoneyTree::PrivateKey.new key: left_from_hash(seed_hash), network: network_key
288
+ @private_key = MoneyTree::PrivateKey.new key: left_from_hash(seed_hash)
299
289
  @chain_code = right_from_hash(seed_hash)
300
290
  @public_key = MoneyTree::PublicKey.new @private_key
301
291
  end
@@ -1,3 +1,3 @@
1
1
  module MoneyTree
2
- VERSION = "0.8.9"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -40,6 +40,12 @@ module MoneyTree
40
40
  EC_POINT_clear_free(point_0_pt)
41
41
  EC_POINT_clear_free(point_1_pt)
42
42
 
43
+ eckey = nil
44
+ group = nil
45
+ sum_point = nil
46
+ point_0_pt = nil
47
+ point_1_pt = nil
48
+
43
49
  hex
44
50
  end
45
51
 
@@ -18,6 +18,15 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ # used with gem i coin-op -P HighSecurity
22
+ spec.cert_chain = ["certs/jvergeldedios.pem"]
23
+ # Sign gem when evaluating spec with `gem` command
24
+ # unless ENV has set a SKIP_GEM_SIGNING
25
+ if ($0 =~ /gem\z/) and not ENV.include?("SKIP_GEM_SIGNING")
26
+ spec.signing_key = File.join(Gem.user_home, ".ssh", "gem-private_key.pem")
27
+ end
28
+
29
+
21
30
  spec.add_dependency "ffi"
22
31
 
23
32
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -56,7 +56,7 @@ describe MoneyTree::Address do
56
56
  end
57
57
 
58
58
  it "returns a testnet address" do
59
- expect(%w(m n)).to include(@address.to_s[0])
59
+ expect(%w(m n)).to include(@address.to_s(network: :bitcoin_testnet)[0])
60
60
  end
61
61
  end
62
62
  end
@@ -24,49 +24,49 @@ describe MoneyTree::Master do
24
24
  end
25
25
 
26
26
  it "generates testnet address" do
27
- expect(%w(m n)).to include(@master.to_address[0])
27
+ expect(%w(m n)).to include(@master.to_address(network: :bitcoin_testnet)[0])
28
28
  end
29
29
 
30
30
  it "generates testnet compressed wif" do
31
- expect(@master.private_key.to_wif[0]).to eql('c')
31
+ expect(@master.private_key.to_wif(network: :bitcoin_testnet)[0]).to eql('c')
32
32
  end
33
33
 
34
34
  it "generates testnet uncompressed wif" do
35
- expect(@master.private_key.to_wif(compressed: false)[0]).to eql('9')
35
+ expect(@master.private_key.to_wif(compressed: false, network: :bitcoin_testnet)[0]).to eql('9')
36
36
  end
37
37
 
38
38
  it "generates testnet serialized private address" do
39
- expect(@master.to_serialized_address(:private).slice(0, 4)).to eql("tprv")
39
+ expect(@master.to_serialized_address(:private, network: :bitcoin_testnet).slice(0, 4)).to eql("tprv")
40
40
  end
41
41
 
42
42
  it "generates testnet serialized public address" do
43
- expect(@master.to_serialized_address.slice(0, 4)).to eql("tpub")
43
+ expect(@master.to_serialized_address(network: :bitcoin_testnet).slice(0, 4)).to eql("tpub")
44
44
  end
45
45
 
46
46
  it "imports from testnet serialized private address" do
47
47
  node = MoneyTree::Node.from_serialized_address 'tprv8ZgxMBicQKsPcuN7bfUZqq78UEYapr3Tzmc9NcDXw8BnBJ47dZYr6SusnfYj7vbAYP9CP8ZiD5aVBTUo1yU5QP56mepKVvuEbu8KZQXMKNE'
48
- expect(node.to_serialized_address(:private)).to eql('tprv8ZgxMBicQKsPcuN7bfUZqq78UEYapr3Tzmc9NcDXw8BnBJ47dZYr6SusnfYj7vbAYP9CP8ZiD5aVBTUo1yU5QP56mepKVvuEbu8KZQXMKNE')
48
+ expect(node.to_serialized_address(:private, network: :bitcoin_testnet)).to eql('tprv8ZgxMBicQKsPcuN7bfUZqq78UEYapr3Tzmc9NcDXw8BnBJ47dZYr6SusnfYj7vbAYP9CP8ZiD5aVBTUo1yU5QP56mepKVvuEbu8KZQXMKNE')
49
49
  end
50
50
 
51
51
  it "imports from testnet serialized public address" do
52
52
  node = MoneyTree::Node.from_serialized_address 'tpubD6NzVbkrYhZ4YA8aUE9bBZTSyHJibBqwDny5urfwDdJc4W8od3y3Ebzy6CqsYn9CCC5P5VQ7CeZYpnT1kX3RPVPysU2rFRvYSj8BCoYYNqT'
53
- expect(%w(m n)).to include(node.public_key.to_s[0])
54
- expect(node.to_serialized_address).to eql('tpubD6NzVbkrYhZ4YA8aUE9bBZTSyHJibBqwDny5urfwDdJc4W8od3y3Ebzy6CqsYn9CCC5P5VQ7CeZYpnT1kX3RPVPysU2rFRvYSj8BCoYYNqT')
53
+ expect(%w(m n)).to include(node.public_key.to_s(network: :bitcoin_testnet)[0])
54
+ expect(node.to_serialized_address(network: :bitcoin_testnet)).to eql('tpubD6NzVbkrYhZ4YA8aUE9bBZTSyHJibBqwDny5urfwDdJc4W8od3y3Ebzy6CqsYn9CCC5P5VQ7CeZYpnT1kX3RPVPysU2rFRvYSj8BCoYYNqT')
55
55
  end
56
56
 
57
57
  it "generates testnet subnodes from serialized private address" do
58
58
  node = MoneyTree::Node.from_serialized_address 'tprv8ZgxMBicQKsPcuN7bfUZqq78UEYapr3Tzmc9NcDXw8BnBJ47dZYr6SusnfYj7vbAYP9CP8ZiD5aVBTUo1yU5QP56mepKVvuEbu8KZQXMKNE'
59
59
  subnode = node.node_for_path('1/1/1')
60
- expect(%w(m n)).to include(subnode.public_key.to_s[0])
61
- expect(subnode.to_serialized_address(:private).slice(0,4)).to eql('tprv')
62
- expect(subnode.to_serialized_address.slice(0,4)).to eql('tpub')
60
+ expect(%w(m n)).to include(subnode.public_key.to_s(network: :bitcoin_testnet)[0])
61
+ expect(subnode.to_serialized_address(:private, network: :bitcoin_testnet).slice(0,4)).to eql('tprv')
62
+ expect(subnode.to_serialized_address(network: :bitcoin_testnet).slice(0,4)).to eql('tpub')
63
63
  end
64
64
 
65
65
  it "generates testnet subnodes from serialized public address" do
66
66
  node = MoneyTree::Node.from_serialized_address 'tpubD6NzVbkrYhZ4YA8aUE9bBZTSyHJibBqwDny5urfwDdJc4W8od3y3Ebzy6CqsYn9CCC5P5VQ7CeZYpnT1kX3RPVPysU2rFRvYSj8BCoYYNqT'
67
67
  subnode = node.node_for_path('1/1/1')
68
- expect(%w(m n)).to include(subnode.public_key.to_s[0])
69
- expect(subnode.to_serialized_address.slice(0,4)).to eql('tpub')
68
+ expect(%w(m n)).to include(subnode.public_key.to_s(network: :bitcoin_testnet)[0])
69
+ expect(subnode.to_serialized_address(network: :bitcoin_testnet).slice(0,4)).to eql('tpub')
70
70
  end
71
71
  end
72
72
 
@@ -799,7 +799,7 @@ describe MoneyTree::Master do
799
799
  it "correctly derives from a node with a chain code represented in 31 bytes" do
800
800
  @node = MoneyTree::Node.from_serialized_address "tpubD6NzVbkrYhZ4WM42MZZmUZ7LjxyjBf5bGjEeLf9nJnMZqocGJWu94drvpqWsE9jE7k3h22v6gjpPGnqgBrqwGsRYwDXVRfQ2M9dfHbXP5zA"
801
801
  @subnode = @node.node_for_path('m/1')
802
- expect(@subnode.to_serialized_address).to eql("tpubDA7bCxb3Nrcz2ChXyPqXxbG4q5oiAZUHR7wD3LAiXukuxmT65weWw84XYmjhkJTkJEM6LhNWioWTpKEkQp7j2fgVccj3PPc271xHDeMsaTY")
802
+ expect(@subnode.to_serialized_address(network: :bitcoin_testnet)).to eql("tpubDA7bCxb3Nrcz2ChXyPqXxbG4q5oiAZUHR7wD3LAiXukuxmT65weWw84XYmjhkJTkJEM6LhNWioWTpKEkQp7j2fgVccj3PPc271xHDeMsaTY")
803
803
  end
804
804
  end
805
805
  end
@@ -45,7 +45,7 @@ describe MoneyTree::PrivateKey do
45
45
  end
46
46
 
47
47
  it "is valid" do
48
- expect(@key.to_wif(compressed: false)).to eql('5JXz5ZyFk31oHVTQxqce7yitCmTAPxBqeGQ4b7H3Aj3L45wUhoa' )
48
+ expect(@key.to_wif(compressed: false)).to eql('5JXz5ZyFk31oHVTQxqce7yitCmTAPxBqeGQ4b7H3Aj3L45wUhoa')
49
49
  end
50
50
  end
51
51
 
@@ -104,7 +104,7 @@ describe MoneyTree::PrivateKey do
104
104
 
105
105
  describe "to_wif" do
106
106
  it "returns same wif" do
107
- expect(@key.to_wif).to eql('cRhes8SBnsF6WizphaRKQKZZfDniDa9Bxcw31yKeEC1KDExhxFgD')
107
+ expect(@key.to_wif(network: :bitcoin_testnet)).to eql('cRhes8SBnsF6WizphaRKQKZZfDniDa9Bxcw31yKeEC1KDExhxFgD')
108
108
  end
109
109
  end
110
110
  end
@@ -161,26 +161,26 @@ describe MoneyTree::PublicKey do
161
161
  context "testnet" do
162
162
  context 'with private key' do
163
163
  before do
164
- @private_key = MoneyTree::PrivateKey.new network: :bitcoin_testnet
164
+ @private_key = MoneyTree::PrivateKey.new
165
165
  @key = MoneyTree::PublicKey.new(@private_key)
166
166
  end
167
167
 
168
168
  it "should have an address starting with m or n" do
169
- expect(%w(m n)).to include(@key.to_s[0])
169
+ expect(%w(m n)).to include(@key.to_s(network: :bitcoin_testnet)[0])
170
170
  end
171
171
 
172
172
  it "should have an uncompressed address starting with m or n" do
173
- expect(%w(m n)).to include(@key.uncompressed.to_s[0])
173
+ expect(%w(m n)).to include(@key.uncompressed.to_s(network: :bitcoin_testnet)[0])
174
174
  end
175
175
  end
176
176
 
177
177
  context 'without private key' do
178
178
  before do
179
- @key = MoneyTree::PublicKey.new('0297b033ba894611345a0e777861237ef1632370fbd58ebe644eb9f3714e8fe2bc', network: :bitcoin_testnet)
179
+ @key = MoneyTree::PublicKey.new('0297b033ba894611345a0e777861237ef1632370fbd58ebe644eb9f3714e8fe2bc')
180
180
  end
181
181
 
182
182
  it "should have an address starting with m or n" do
183
- expect(%w(m n)).to include(@key.to_s[0])
183
+ expect(%w(m n)).to include(@key.to_s(network: :bitcoin_testnet)[0])
184
184
  end
185
185
  end
186
186
  end
@@ -1,2 +1,3 @@
1
1
  require 'simplecov'
2
2
  require 'money-tree'
3
+ require 'pry'
metadata CHANGED
@@ -1,14 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money-tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.9
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Winkelspecht
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
11
- date: 2015-01-21 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDXDCCAkSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA6MQ8wDQYDVQQDDAZqdWxp
14
+ YW4xEzARBgoJkiaJk/IsZAEZFgNnZW0xEjAQBgoJkiaJk/IsZAEZFgJjbzAeFw0x
15
+ NTA0MDMwODAwMTdaFw0xNjA0MDIwODAwMTdaMDoxDzANBgNVBAMMBmp1bGlhbjET
16
+ MBEGCgmSJomT8ixkARkWA2dlbTESMBAGCgmSJomT8ixkARkWAmNvMIIBIjANBgkq
17
+ hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp0qCsOUQyTRA4f7WxoU2ctpUO5+eLZw8
18
+ ILvHJy/0dC2nnIgib+FaFA8TRIGw6fjX2hQ43QJyO36zkjUhAwNu/+TBCfG+Grut
19
+ 2dI9XmqU5Z6PvvXRj6Gu5IkDeIVDKILZv3bDugHJalre4BUKnwPYv5WpZ/e/c6+z
20
+ E4fwe4ZQzqslSXZo0o/wFvs5dGuIoP93bazSeqddre0JKFFiEP/SNGP9e/lXEd2V
21
+ rLFYAY409no9J+VQOHP0Nu9ShlCZp8M45abKd2ykuSDaT6jH9YcUHBr3/IEsA4+f
22
+ DypeS1ySVvad+o8iTnfz1Hyohz4ORm3spf0BOtGI/Swbv3LObZJqkwIDAQABo20w
23
+ azAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUERhBDW/kkq7tz2hN
24
+ hPNHtounnkowGAYDVR0RBBEwD4ENanVsaWFuQGdlbS5jbzAYBgNVHRIEETAPgQ1q
25
+ dWxpYW5AZ2VtLmNvMA0GCSqGSIb3DQEBBQUAA4IBAQAgnumhg8ST8JohYWcoDoQt
26
+ 3BUG5rbfJ/qE0utOt6esi9d6Vz6YHpiT08woaj68OWl9U9N4vjox+ckkTRs93KBd
27
+ y3thnK9cIEAzoEZs3BBguXYOoFLughGD7hEuLlRYbwZzyIdzx/XdLgsy5Di8Gqaa
28
+ RKurfXP+dERQww34CUhmhOLO4/rYGqaD88so0MzCImgS+OX+G4ppqd38iQpaxCHL
29
+ tdc4VS7IlSRxlZ3dBOgiigy9GXpJ+7F831AqjxL39EPwdr7RguTNz+pi//RKaT/U
30
+ IlpVB+Xfk0vQdP7iYfjGxDzUf0FACMjsR95waJmadKW1Iy6STw2hwPhYIQz1Hu1A
31
+ -----END CERTIFICATE-----
32
+ date: 2015-05-19 00:00:00.000000000 Z
12
33
  dependencies:
13
34
  - !ruby/object:Gem::Dependency
14
35
  name: ffi
Binary file