money-tree 0.10.0 → 0.11.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
  SHA256:
3
- metadata.gz: e6b1fd18c035198917d9939d44f6bcbbe4ae69ef168af5de52ab32f5778662b1
4
- data.tar.gz: 31ef2d35cd3d2f10cf40d7fe44787a38857c1c79173494f97d0d296f7828bfba
3
+ metadata.gz: 040b86e807e6dea0ebf4dfc4b5e508e3f9ef673c94b95a210a18c125d8857974
4
+ data.tar.gz: '01800e0fb32058488fd01f1a8f2be3539788c7d0bebc0021fd49776fdde947a4'
5
5
  SHA512:
6
- metadata.gz: 03c0b6c55c8f290f10989870d559904a644a68f441cc0ae6498d9cde12bc4853f63babc6ce68d5ad1dfbfb3f6a67b0b4b400053fdddacb62faa9d01adc43f765
7
- data.tar.gz: 8c37b6e7386c60be7ac9797a248039b88ff39b0f46438a07c46aa363b8c8fa30160cdeb0f6d5d54f92fc0b512f437e6a73488cc12e355c25b04fb9dcb7af5d33
6
+ metadata.gz: 70a6465799b1f7140a2e45c2ded416b41e4b64a7801b57325ed20cea470c92cad96e7644596d523a192254e7284eb772406e90af0a797f5b367304cbe2e9b725
7
+ data.tar.gz: 2d0c6bea3a33f161cf30a3400d3f75b6119098f035eca6cdac076c11c03596a2e0e205456b1e3ea2453f2ad1e58fd7edec91ff21ec1a8fd515c2d7836169762c
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Spec
3
+
4
+ on:
5
+ pull_request:
6
+ branches:
7
+ - master
8
+ push:
9
+ branches:
10
+ - master
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, macos-latest]
19
+ ruby: ['2.7', '3.0']
20
+ steps:
21
+ - uses: actions/checkout@v2
22
+ - uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: false
26
+ - name: Install Dependencies
27
+ run: |
28
+ bundle install
29
+ - name: Run Tests
30
+ run: |
31
+ bundle exec rspec
data/README.md CHANGED
@@ -1,13 +1,23 @@
1
- [![Build Status](https://travis-ci.org/GemHQ/money-tree.png)](https://travis-ci.org/GemHQ/money-tree) [![Coverage Status](https://img.shields.io/coveralls/GemHQ/money-tree.svg)](https://coveralls.io/r/GemHQ/money-tree?branch=master) [![Code Climate](https://codeclimate.com/github/GemHQ/money-tree.png)](https://codeclimate.com/github/GemHQ/money-tree) [![Gem Version](https://badge.fury.io/rb/money-tree.png)](http://badge.fury.io/rb/money-tree)
2
1
  # MoneyTree
2
+
3
+ [![GitHub release (latest by date)](https://img.shields.io/github/v/release/GemHQ/money-tree)](https://github.com/GemHQ/money-tree/releases)
4
+ [![Gem](https://img.shields.io/gem/v/money-tree)](https://rubygems.org/gems/money-tree)
5
+ [![Gem](https://img.shields.io/gem/dt/money-tree)](https://rubygems.org/gems/money-tree)
6
+ [![GitHub top language](https://img.shields.io/github/languages/top/GemHQ/money-tree?color=red)](https://github.com/GemHQ/money-tree/pulse)
7
+
8
+ [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/GemHQ/money-tree/Spec)](https://github.com/GemHQ/money-tree/actions)
9
+ [![Coverage Status](https://img.shields.io/coveralls/GemHQ/money-tree.svg)](https://coveralls.io/r/GemHQ/money-tree?branch=master)
10
+ [![Code Climate](https://codeclimate.com/github/GemHQ/money-tree.png)](https://codeclimate.com/github/GemHQ/money-tree)
11
+ [![GitHub](https://img.shields.io/github/license/GemHQ/money-tree)](LICENSE)
12
+
3
13
  ### RSpec tested. Big Brother removed.
4
14
 
5
15
  MoneyTree is a Ruby implementation of Bitcoin Wallets. Specifically, it supports [Hierachical Deterministic wallets](https://en.bitcoin.it/wiki/Deterministic_Wallet) according to the protocol specified in [BIP0032](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki).
6
16
 
7
17
  ___
8
- If you find this helpful, please consider a small Bitcoin donation to 1nj2kie1hATcFbAaD7dEY53QaxNgt4KBp
18
+ If you find this helpful, please consider a small Bitcoin donation to `1nj2kie1hATcFbAaD7dEY53QaxNgt4KBp`.
9
19
 
10
- ![Donate BTC](https://raw.github.com/wink/money-tree/master/donation_btc_qr_code.gif)
20
+ ![Donate BTC](./.github/donation_btc_qr_code.gif)
11
21
  ___
12
22
 
13
23
  ## Why would I want an HD Wallet?
@@ -163,7 +173,7 @@ Because we need multiple pieces of info to reconstruct nodes in a tree, when we'
163
173
  "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"
164
174
  ```
165
175
 
166
- In addition to the key and the chain code, this encoding also includes info about the depth and index of the key, along with a fingerprint of its parent key (which I presume is for quickly sorting a big pile of keys into a tree).
176
+ In addition to the key and the chain code, this encoding also includes info about the depth and index of the key, along with a fingerprint of its parent key (which I presume is for quickly sorting a big pile of keys into a tree).
167
177
 
168
178
  These are the addresses that you should use to represent each node in the tree structure, however these are NOT the bitcoin addresses you should pass around for receiving money. These are more for storing inside a wallet file so that you can reconstruct the tree.
169
179
 
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task :default => :spec
@@ -1,13 +1,13 @@
1
1
  module MoneyTree
2
2
  class Address
3
3
  attr_reader :private_key, :public_key
4
-
4
+
5
5
  def initialize(opts = {})
6
6
  private_key = opts.delete(:private_key)
7
7
  @private_key = MoneyTree::PrivateKey.new({ key: private_key }.merge(opts))
8
8
  @public_key = MoneyTree::PublicKey.new(@private_key, opts)
9
9
  end
10
-
10
+
11
11
  def to_s(network: :bitcoin)
12
12
  public_key.to_s(network: network)
13
13
  end
@@ -90,7 +90,12 @@ module MoneyTree
90
90
  left_int = left_from_hash(hash)
91
91
  raise InvalidKeyForIndex, 'greater than or equal to order' if left_int >= MoneyTree::Key::ORDER # very low probability
92
92
  factor = BN.new left_int.to_s
93
- child_public_key = public_key.uncompressed.group.generator.mul(factor).add(public_key.uncompressed.point).to_bn.to_i
93
+
94
+ gen_point = public_key.uncompressed.group.generator.mul(factor)
95
+
96
+ sum_point_hex = MoneyTree::OpenSSLExtensions.add(gen_point, public_key.uncompressed.point)
97
+ child_public_key = OpenSSL::PKey::EC::Point.new(public_key.group, OpenSSL::BN.new(sum_point_hex, 16)).to_bn.to_i
98
+
94
99
  raise InvalidKeyForIndex, 'at infinity' if child_public_key == 1/0.0 # very low probability
95
100
  child_chain_code = right_from_hash(hash)
96
101
  return child_public_key, child_chain_code
@@ -4,11 +4,11 @@ require 'base64'
4
4
  module MoneyTree
5
5
  module Support
6
6
  include OpenSSL
7
-
7
+
8
8
  INT32_MAX = 256 ** [1].pack("L*").size
9
9
  INT64_MAX = 256 ** [1].pack("Q*").size
10
10
  BASE58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
11
-
11
+
12
12
  def int_to_base58(int_val, leading_zero_bytes=0)
13
13
  base58_val, base = '', BASE58_CHARS.size
14
14
  while int_val > 0
@@ -40,7 +40,7 @@ module MoneyTree
40
40
  s
41
41
  end
42
42
  alias_method :base58_to_hex, :decode_base58
43
-
43
+
44
44
  def to_serialized_base58(hex)
45
45
  hash = sha256 hex
46
46
  hash = sha256 hash
@@ -48,7 +48,7 @@ module MoneyTree
48
48
  address = hex + checksum
49
49
  encode_base58 address
50
50
  end
51
-
51
+
52
52
  def from_serialized_base58(base58)
53
53
  hex = decode_base58 base58
54
54
  checksum = hex.slice!(-8..-1)
@@ -56,45 +56,45 @@ module MoneyTree
56
56
  raise EncodingError unless checksum == compare_checksum
57
57
  hex
58
58
  end
59
-
59
+
60
60
  def digestify(digest_type, source, opts = {})
61
61
  source = [source].pack("H*") unless opts[:ascii]
62
62
  bytes_to_hex Digest.digest(digest_type, source)
63
63
  end
64
-
64
+
65
65
  def sha256(source, opts = {})
66
66
  digestify('SHA256', source, opts)
67
67
  end
68
-
68
+
69
69
  def ripemd160(source, opts = {})
70
70
  digestify('RIPEMD160', source, opts)
71
71
  end
72
-
72
+
73
73
  def encode_base64(hex)
74
74
  Base64.encode64([hex].pack("H*")).chomp
75
75
  end
76
-
76
+
77
77
  def decode_base64(base64)
78
78
  Base64.decode64(base64).unpack("H*")[0]
79
79
  end
80
-
80
+
81
81
  def hmac_sha512(key, message)
82
82
  digest = Digest::SHA512.new
83
83
  HMAC.digest digest, key, message
84
84
  end
85
-
85
+
86
86
  def hmac_sha512_hex(key, message)
87
87
  md = hmac_sha512(key, message)
88
88
  md.unpack("H*").first.rjust(64, '0')
89
89
  end
90
-
90
+
91
91
  def bytes_to_int(bytes, base = 16)
92
92
  if bytes.is_a?(Array)
93
93
  bytes = bytes.pack("C*")
94
94
  end
95
95
  bytes.unpack("H*")[0].to_i(16)
96
96
  end
97
-
97
+
98
98
  def int_to_hex(i, size=nil)
99
99
  hex = i.to_s(16).downcase
100
100
  if (hex.size % 2) != 0
@@ -107,19 +107,19 @@ module MoneyTree
107
107
  hex
108
108
  end
109
109
  end
110
-
110
+
111
111
  def int_to_bytes(i)
112
112
  [int_to_hex(i)].pack("H*")
113
113
  end
114
-
114
+
115
115
  def bytes_to_hex(bytes)
116
116
  bytes.unpack("H*")[0].downcase
117
117
  end
118
-
118
+
119
119
  def hex_to_bytes(hex)
120
120
  [hex].pack("H*")
121
121
  end
122
-
122
+
123
123
  def hex_to_int(hex)
124
124
  hex.to_i(16)
125
125
  end
@@ -1,3 +1,3 @@
1
1
  module MoneyTree
2
- VERSION = "0.10.0"
2
+ VERSION = "0.11.0"
3
3
  end
data/lib/money-tree.rb CHANGED
@@ -8,5 +8,4 @@ require "money-tree/networks"
8
8
  require "money-tree/node"
9
9
 
10
10
  module MoneyTree
11
-
12
11
  end
@@ -1,73 +1,28 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
3
  require 'openssl'
4
- require 'ffi'
5
4
 
6
5
  module MoneyTree
7
6
  module OpenSSLExtensions
8
- extend FFI::Library
9
- ffi_lib ['libssl.so.1.0.0', 'libssl.so.10', 'libssl1.0.0', 'ssl']
10
-
11
- NID_secp256k1 = 714
12
- POINT_CONVERSION_COMPRESSED = 2
13
- POINT_CONVERSION_UNCOMPRESSED = 4
14
-
15
- attach_function :EC_KEY_free, [:pointer], :int
16
- attach_function :EC_KEY_get0_group, [:pointer], :pointer
17
- attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
18
- attach_function :EC_POINT_clear_free, [:pointer], :int
19
- attach_function :EC_POINT_add, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
20
- attach_function :EC_POINT_point2hex, [:pointer, :pointer, :int, :pointer], :string
21
- attach_function :EC_POINT_hex2point, [:pointer, :string, :pointer, :pointer], :pointer
22
- attach_function :EC_POINT_new, [:pointer], :pointer
23
-
24
7
  def self.add(point_0, point_1)
25
8
  validate_points(point_0, point_1)
26
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
27
- group = EC_KEY_get0_group(eckey)
28
-
9
+ group = OpenSSL::PKey::EC::Group.new('secp256k1')
29
10
  point_0_hex = point_0.to_bn.to_s(16)
30
- point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
11
+ point_0_pt = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(point_0_hex, 16))
31
12
  point_1_hex = point_1.to_bn.to_s(16)
32
- point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
33
-
34
- sum_point = EC_POINT_new(group)
35
- success = EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
36
- hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
37
-
38
- EC_KEY_free(eckey)
39
- EC_POINT_clear_free(sum_point)
40
- EC_POINT_clear_free(point_0_pt)
41
- EC_POINT_clear_free(point_1_pt)
42
-
43
- eckey = nil
44
- group = nil
45
- sum_point = nil
46
- point_0_pt = nil
47
- point_1_pt = nil
48
-
49
- hex
13
+ point_1_pt = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(point_1_hex, 16))
14
+ sum_point = point_0_pt.add(point_1_pt)
15
+ sum_point.to_bn.to_s(16)
50
16
  end
51
17
 
52
18
  def self.validate_points(*points)
53
19
  points.each do |point|
54
20
  if !point.is_a?(OpenSSL::PKey::EC::Point)
55
- raise ArgumentError, "point must be an OpenSSL::PKey::EC::Point object"
21
+ raise ArgumentError, "point must be an OpenSSL::PKey::EC::Point object"
56
22
  elsif point.infinity?
57
- raise ArgumentError, "point must not be infinity"
23
+ raise ArgumentError, "point must not be infinity"
58
24
  end
59
25
  end
60
26
  end
61
27
  end
62
28
  end
63
-
64
-
65
- class OpenSSL::PKey::EC::Point
66
- include MoneyTree::OpenSSLExtensions
67
-
68
- def add(point)
69
- sum_point_hex = MoneyTree::OpenSSLExtensions.add(self, point)
70
- self.class.new group, OpenSSL::BN.new(sum_point_hex, 16)
71
- end
72
-
73
- end
data/money-tree.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'money-tree/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "money-tree"
8
8
  spec.version = MoneyTree::VERSION
9
- spec.authors = ["Micah Winkelspecht"]
10
- spec.email = ["winkelspecht@gmail.com"]
9
+ spec.authors = ["Micah Winkelspecht", "Afri Schoedon"]
10
+ spec.email = ["winkelspecht@gmail.com", "gems@q9f.cc"]
11
11
  spec.description = %q{A Ruby Gem implementation of Bitcoin HD Wallets}
12
12
  spec.summary = %q{Bitcoin Hierarchical Deterministic Wallets in Ruby! (Bitcoin standard BIP0032)}
13
13
  spec.homepage = "https://github.com/gemhq/money-tree"
@@ -17,22 +17,11 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
-
21
- # used with gem install ... -P HighSecurity
22
- spec.cert_chain = ["certs/mattatgemco.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
20
 
29
-
30
- spec.add_dependency "ffi"
31
-
32
- spec.add_development_dependency "bundler", "~> 1.3"
33
- spec.add_development_dependency "rake"
34
- spec.add_development_dependency "rspec"
35
- spec.add_development_dependency "simplecov"
36
- spec.add_development_dependency "coveralls"
37
- spec.add_development_dependency "pry"
21
+ spec.add_dependency 'openssl', '>= 2.2'
22
+
23
+ spec.add_development_dependency "bundler", "~> 2.2"
24
+ spec.add_development_dependency "rake", "~> 13.0"
25
+ spec.add_development_dependency "rspec", "~> 3.10"
26
+ spec.add_development_dependency "pry", "~> 0.4"
38
27
  end
@@ -4,14 +4,20 @@ describe MoneyTree::Address do
4
4
  describe "initialize" do
5
5
  it "generates a private key by default" do
6
6
  address = MoneyTree::Address.new
7
+ expect(address).to be
8
+ expect(address).to be_instance_of MoneyTree::Address
9
+ expect(address.private_key).to be_instance_of MoneyTree::PrivateKey
7
10
  expect(address.private_key.key.length).to eql(64)
8
11
  end
9
-
12
+
10
13
  it "generates a public key by default" do
11
14
  address = MoneyTree::Address.new
15
+ expect(address).to be
16
+ expect(address).to be_instance_of MoneyTree::Address
17
+ expect(address.public_key).to be_instance_of MoneyTree::PublicKey
12
18
  expect(address.public_key.key.length).to eql(66)
13
19
  end
14
-
20
+
15
21
  it "imports a private key in hex form" do
16
22
  address = MoneyTree::Address.new private_key: "5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b"
17
23
  expect(address.private_key.key).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
@@ -20,36 +26,46 @@ describe MoneyTree::Address do
20
26
  expect(address.private_key.to_s).to eql("KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK")
21
27
  expect(address.public_key.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
22
28
  end
23
-
29
+
24
30
  it "imports a private key in compressed wif format" do
25
31
  address = MoneyTree::Address.new private_key: "KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK"
26
32
  expect(address.private_key.key).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
27
33
  expect(address.public_key.key).to eql("022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b")
28
34
  expect(address.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
29
35
  end
30
-
36
+
31
37
  it "imports a private key in uncompressed wif format" do
32
38
  address = MoneyTree::Address.new private_key: "5JXz5ZyFk31oHVTQxqce7yitCmTAPxBqeGQ4b7H3Aj3L45wUhoa"
33
39
  expect(address.private_key.key).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
34
40
  expect(address.public_key.key).to eql("022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b")
35
41
  end
36
42
  end
37
-
43
+
38
44
  describe "to_s" do
39
45
  before do
40
46
  @address = MoneyTree::Address.new private_key: "5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b"
41
47
  end
42
-
48
+
43
49
  it "returns compressed base58 public key" do
44
50
  expect(@address.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
45
51
  expect(@address.public_key.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
46
52
  end
47
-
53
+
48
54
  it "returns compressed WIF private key" do
49
55
  expect(@address.private_key.to_s).to eql("KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK")
50
56
  end
51
57
  end
52
58
 
59
+ context "bitcoin wiki" do
60
+ # ref https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
61
+ subject(:wiki) { MoneyTree::Address.new private_key: '18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725' }
62
+
63
+ it "always regenerates the bitcoin wiki example" do
64
+ expect(wiki.public_key.key).to eq "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
65
+ expect(wiki.to_s).to eq "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
66
+ end
67
+ end
68
+
53
69
  context "testnet3" do
54
70
  before do
55
71
  @address = MoneyTree::Address.new network: :bitcoin_testnet
@@ -1,5 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
+ FIXED_KEY1 = <<-fixed_key
4
+ -----BEGIN EC PRIVATE KEY-----
5
+ MHQCAQEEIOvYaAN53KFhyLIElYFZCpm/Q2wq72Uu0kRcKeCDdlJVoAcGBSuBBAAK
6
+ oUQDQgAE4cdbt+NxMCBLg0cQYqo/UEwfzAONpz/n7ux+QrdKuH9NRulf9D4996x5
7
+ r7QBY+l5GJ+RgzLoXbFjPyPQtCV+/Q==
8
+ -----END EC PRIVATE KEY-----
9
+ fixed_key
10
+
11
+ FIXED_KEY2 = <<-fixed_key
12
+ -----BEGIN EC PRIVATE KEY-----
13
+ MHQCAQEEIP6nKLMEcH9R3hv695rCUl9OV+ueC9UX18F2PIH5wcFpoAcGBSuBBAAK
14
+ oUQDQgAErilvn3ms9cKHLNHHegiUU+NuW8c2f223vYInEV+s9ZNSGd28usAXZ6lN
15
+ O2zE534+k09fFe2skHtdoXbLJuZV8g==
16
+ -----END EC PRIVATE KEY-----
17
+ fixed_key
18
+
19
+ FIXED_SUM = "04F3C291542F410F61D61861D911F71ABD320A7B77ED571F92FEC533F61549BF218BAA47BD134847D89917F7483AFE20CCD9B1A4CBDFC443B389D1313B48E018F4"
20
+
3
21
  describe MoneyTree::OpenSSLExtensions do
4
22
  include MoneyTree::OpenSSLExtensions
5
23
 
@@ -8,8 +26,15 @@ describe MoneyTree::OpenSSLExtensions do
8
26
  let(:key2) { OpenSSL::PKey::EC.new("secp256k1").generate_key }
9
27
  let(:point_1) { key1.public_key }
10
28
  let(:point_2) { key2.public_key }
29
+
11
30
  let(:point_infinity) { key1.public_key.set_to_infinity! }
12
31
 
32
+ let(:fixed_key1) { OpenSSL::PKey::EC.new(FIXED_KEY1) }
33
+ let(:fixed_key2) { OpenSSL::PKey::EC.new(FIXED_KEY2) }
34
+ let(:fixed_point1) { fixed_key1.public_key }
35
+ let(:fixed_point2) { fixed_key2.public_key }
36
+ let(:fixed_sum_point) { OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC::Group.new("secp256k1"), OpenSSL::BN.new(FIXED_SUM, 16)) }
37
+
13
38
  it "requires valid points" do
14
39
  expect { MoneyTree::OpenSSLExtensions.add(0, 0) }.to raise_error(ArgumentError)
15
40
  expect { MoneyTree::OpenSSLExtensions.add(nil, nil) }.to raise_error(ArgumentError)
@@ -17,7 +42,30 @@ describe MoneyTree::OpenSSLExtensions do
17
42
  expect { MoneyTree::OpenSSLExtensions.add(0, point_2) }.to raise_error(ArgumentError)
18
43
  expect { MoneyTree::OpenSSLExtensions.add(point_infinity, point_2) }.to raise_error(ArgumentError)
19
44
  expect { MoneyTree::OpenSSLExtensions.add(point_1, point_2) }.to_not raise_error
45
+ expect { MoneyTree::OpenSSLExtensions.validate_points(point_1) }.to_not raise_error
46
+ end
47
+
48
+ it "validates points correctly" do
49
+ expect { MoneyTree::OpenSSLExtensions.validate_points(point_1) }.to_not raise_error
50
+ expect { MoneyTree::OpenSSLExtensions.validate_points(point_2) }.to_not raise_error
51
+ expect { MoneyTree::OpenSSLExtensions.validate_points(point_infinity) }.to raise_error(ArgumentError)
52
+ end
53
+
54
+ it "should add points correctly" do
55
+ result = MoneyTree::OpenSSLExtensions.add(fixed_point1, fixed_point2)
56
+
57
+ expect(result).to eql(FIXED_SUM)
58
+
59
+ group = OpenSSL::PKey::EC::Group.new("secp256k1")
60
+ result_point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(result, 16))
61
+
62
+ expect(result_point).to eql(fixed_sum_point)
63
+ end
64
+
65
+ it 'should be able to create the same hex output for the point' do
66
+ hex_output = fixed_sum_point.to_bn.to_s(16)
67
+
68
+ expect(hex_output).to eq(FIXED_SUM)
20
69
  end
21
70
  end
22
-
23
71
  end
@@ -4,7 +4,7 @@ describe MoneyTree::PrivateKey do
4
4
  before do
5
5
  @key = MoneyTree::PrivateKey.new key: "5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b"
6
6
  end
7
-
7
+
8
8
  describe "to_hex" do
9
9
  it "has 64 characters" do
10
10
  # must always be 64 characters - leading zeroes need to be preserved!
@@ -15,81 +15,81 @@ describe MoneyTree::PrivateKey do
15
15
  master = MoneyTree::Master.new seed_hex: "9cf6b6e8451c7d551cb402e2997566e5c7c258543eadb184f9f39322b2e6959b"
16
16
  expect(master.node_for_path("m/427").private_key.to_hex.length).to eql(64)
17
17
  end
18
-
18
+
19
19
  it "is a valid hex" do
20
- expect(@key.to_hex).to eql('5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b' )
20
+ expect(@key.to_hex).to eql('5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b')
21
21
  end
22
22
  end
23
-
23
+
24
24
  describe "to_wif" do
25
25
  it "is a 52 character base58 key" do
26
26
  expect(@key.to_wif.length).to eql(52)
27
27
  end
28
-
28
+
29
29
  it "starts with K or L" do
30
30
  expect(%w(K L)).to include(@key.to_wif[0])
31
31
  end
32
-
32
+
33
33
  it "is a valid compressed wif" do
34
- expect(@key.to_wif).to eql('KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK' )
34
+ expect(@key.to_wif).to eql('KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK')
35
35
  end
36
36
  end
37
-
37
+
38
38
  describe "to_wif(compressed: false)" do
39
39
  it "is a 51 character base58 key" do
40
40
  expect(@key.to_wif(compressed: false).length).to eql(51)
41
41
  end
42
-
42
+
43
43
  it "starts with 5" do
44
44
  expect(@key.to_wif(compressed: false)[0]).to eql('5')
45
45
  end
46
-
46
+
47
47
  it "is valid" do
48
48
  expect(@key.to_wif(compressed: false)).to eql('5JXz5ZyFk31oHVTQxqce7yitCmTAPxBqeGQ4b7H3Aj3L45wUhoa')
49
49
  end
50
50
  end
51
-
51
+
52
52
  describe "from_wif(wif)" do
53
53
  it "returns the key from a wif" do
54
54
  expect(@key.from_wif("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ")).to eql('0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d')
55
55
  end
56
-
56
+
57
57
  it "raises an error on bad checksum" do
58
58
  expect { @key.from_wif("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTBADTJ") }.to raise_error(MoneyTree::Key::InvalidWIFFormat)
59
59
  end
60
60
  end
61
-
61
+
62
62
  describe "to_base64" do
63
63
  it "has 44 characters" do
64
64
  expect(@key.to_base64.length).to eql(44)
65
65
  end
66
-
66
+
67
67
  it "is a valid base64" do
68
- expect(@key.to_base64).to eql('Xq5Tdftfeg6mUFZjY776KDDvRBvcsZGYrfMY+u6G1ks=' )
68
+ expect(@key.to_base64).to eql('Xq5Tdftfeg6mUFZjY776KDDvRBvcsZGYrfMY+u6G1ks=')
69
69
  end
70
70
  end
71
-
71
+
72
72
  describe "from_base64(base64_key)" do
73
73
  it "parses base64 key" do
74
74
  @key = MoneyTree::PrivateKey.new(key: "Xq5Tdftfeg6mUFZjY776KDDvRBvcsZGYrfMY+u6G1ks=")
75
75
  expect(@key.to_hex).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
76
76
  end
77
-
77
+
78
78
  it "returns the key from base64 encoding" do
79
79
  expect(@key.from_base64("Xq5Tdftfeg6mUFZjY776KDDvRBvcsZGYrfMY+u6G1ks=")).to eql('5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b')
80
80
  end
81
-
81
+
82
82
  it "raises an error on bad encoding" do
83
83
  expect { @key.from_base64("Xq5Tdftfeg6mUFZjY776KD&%#BbadBADrfMY+u6G1ks=") }.to raise_error(MoneyTree::Key::InvalidBase64Format)
84
84
  end
85
85
  end
86
-
86
+
87
87
  describe "valid?(eckey)" do
88
88
  it "checks for a valid key" do
89
89
  expect(@key.valid?).to be_truthy
90
90
  end
91
91
  end
92
-
92
+
93
93
  describe "parse_raw_key" do
94
94
  it "returns error if key is not Bignum, hex, base64, or wif formatted" do
95
95
  expect { @key = MoneyTree::PrivateKey.new(key: "Thisisnotakey") }.to raise_error(MoneyTree::Key::KeyFormatNotFound)
@@ -1,111 +1,111 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MoneyTree::PublicKey do
4
-
4
+
5
5
  describe "with a private key" do
6
6
  before do
7
7
  @private_key = MoneyTree::PrivateKey.new key: "5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b"
8
8
  @key = MoneyTree::PublicKey.new @private_key
9
9
  end
10
-
10
+
11
11
  describe "to_hex(compressed: false)" do
12
12
  it "has 65 bytes" do
13
13
  expect(@key.uncompressed.to_hex.length).to eql(130)
14
14
  end
15
-
15
+
16
16
  it "is a valid hex" do
17
- expect(@key.uncompressed.to_hex).to eql('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4' )
17
+ expect(@key.uncompressed.to_hex).to eql('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4')
18
18
  end
19
19
  end
20
-
20
+
21
21
  describe "to_hex" do
22
22
  it "has 33 bytes" do
23
23
  expect(@key.to_hex.length).to eql(66)
24
24
  end
25
-
25
+
26
26
  it "is a valid compressed hex" do
27
- expect(@key.to_hex).to eql('022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b' )
27
+ expect(@key.to_hex).to eql('022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b')
28
28
  end
29
29
  end
30
-
30
+
31
31
  describe "to_fingerprint" do
32
32
  it "returns a valid fingerprint" do
33
33
  expect(@key.to_fingerprint).to eql("1fddf42e")
34
34
  end
35
35
  end
36
-
36
+
37
37
  describe "to_address(compressed: false)" do
38
38
  it "has 34 characters" do
39
39
  expect(@key.uncompressed.to_address.length).to eql(34)
40
40
  end
41
-
41
+
42
42
  it "is a valid bitcoin address" do
43
- expect(@key.uncompressed.to_address).to eql('133bJA2xoVqBUsiR3uSkciMo5r15fLAaZg' )
43
+ expect(@key.uncompressed.to_address).to eql('133bJA2xoVqBUsiR3uSkciMo5r15fLAaZg')
44
44
  end
45
45
  end
46
-
46
+
47
47
  describe "to_compressed_address" do
48
48
  it "has 34 characters" do
49
49
  expect(@key.to_address.length).to eql(34)
50
50
  end
51
-
51
+
52
52
  it "is a valid compressed bitcoin address" do
53
- expect(@key.to_address).to eql('13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe' )
53
+ expect(@key.to_address).to eql('13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe')
54
54
  end
55
55
  end
56
56
  end
57
-
57
+
58
58
  describe "without a private key" do
59
59
  before do
60
60
  @key = MoneyTree::PublicKey.new '042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4'
61
61
  end
62
-
62
+
63
63
  describe "to_hex(compressed: false)" do
64
64
  it "has 65 bytes" do
65
65
  expect(@key.uncompressed.to_hex.length).to eql(130)
66
66
  end
67
-
67
+
68
68
  it "is a valid hex" do
69
- expect(@key.uncompressed.to_hex).to eql('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4' )
69
+ expect(@key.uncompressed.to_hex).to eql('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4')
70
70
  end
71
71
  end
72
-
72
+
73
73
  describe "to_hex" do
74
74
  it "has 33 bytes" do
75
75
  expect(@key.compressed.to_hex.length).to eql(66)
76
76
  end
77
-
77
+
78
78
  it "is a valid compressed hex" do
79
- expect(@key.compressed.to_hex).to eql('022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b' )
79
+ expect(@key.compressed.to_hex).to eql('022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b')
80
80
  end
81
81
  end
82
-
82
+
83
83
  describe "to_fingerprint" do
84
84
  it "returns a valid fingerprint" do
85
85
  expect(@key.compressed.to_fingerprint).to eql("1fddf42e")
86
86
  end
87
87
  end
88
-
88
+
89
89
  describe "to_address(compressed: false)" do
90
90
  it "has 34 characters" do
91
91
  expect(@key.uncompressed.to_address.length).to eql(34)
92
92
  end
93
-
93
+
94
94
  it "is a valid bitcoin address" do
95
- expect(@key.uncompressed.to_address).to eql('133bJA2xoVqBUsiR3uSkciMo5r15fLAaZg' )
95
+ expect(@key.uncompressed.to_address).to eql('133bJA2xoVqBUsiR3uSkciMo5r15fLAaZg')
96
96
  end
97
97
  end
98
-
98
+
99
99
  describe "to_compressed_address" do
100
100
  it "has 34 characters" do
101
101
  expect(@key.compressed.to_address.length).to eql(34)
102
102
  end
103
-
103
+
104
104
  it "is a valid compressed bitcoin address" do
105
- expect(@key.compressed.to_address).to eql('13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe' )
105
+ expect(@key.compressed.to_address).to eql('13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe')
106
106
  end
107
107
  end
108
-
108
+
109
109
  describe "#compression" do
110
110
  it "returns current compression setting" do
111
111
  @key.compression = :uncompressed
@@ -115,7 +115,7 @@ describe MoneyTree::PublicKey do
115
115
  end
116
116
  end
117
117
  end
118
-
118
+
119
119
  describe "with a bad key" do
120
120
  it "raises KeyFormatNotFound" do
121
121
  expect { @key = MoneyTree::PublicKey.new 'THISISNOTAVALIDKEY' }.to raise_error(MoneyTree::Key::KeyFormatNotFound)
@@ -125,7 +125,7 @@ describe MoneyTree::PublicKey do
125
125
  describe "recalcuating public key" do
126
126
  it "produces same results" do
127
127
  results = []
128
- 100.times do
128
+ 100.times do
129
129
  results << MoneyTree::PublicKey.new('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4').to_s
130
130
  end
131
131
  expect(results.uniq.length).to eql(1)
@@ -158,6 +158,18 @@ describe MoneyTree::PublicKey do
158
158
  end
159
159
  end
160
160
 
161
+ context "wobine's blackboard 101 series" do
162
+ # ref https://github.com/wobine/blackboard101/blob/e991ea0b98fd26059bf3806e5749b5e5f737e791/EllipticCurvesPart4-PrivateKeyToPublicKey.py
163
+ subject(:wobine) { MoneyTree::PrivateKey.new key: 'A0DC65FFCA799873CBEA0AC274015B9526505DAAAED385155425F7337704883E' }
164
+
165
+ it "always recovers wobine's public keys" do
166
+ expect(wobine.key).to eq 'a0dc65ffca799873cbea0ac274015b9526505daaaed385155425f7337704883e'
167
+ public_key = MoneyTree::PublicKey.new wobine
168
+ expect(public_key.key).to eq '020791dc70b75aa995213244ad3f4886d74d61ccd3ef658243fcad14c9ccee2b0a'
169
+ expect(public_key.uncompressed.to_hex).to eq '040791dc70b75aa995213244ad3f4886d74d61ccd3ef658243fcad14c9ccee2b0aa762fbc6ac0921b8f17025bb8458b92794ae87a133894d70d7995fc0b6b5ab90'
170
+ end
171
+ end
172
+
161
173
  context "testnet" do
162
174
  context 'with private key' do
163
175
  before do
@@ -10,20 +10,20 @@ describe MoneyTree::Support do
10
10
  expect(sha256("8147786c4d15106333bf278d71dadaf1079ef2d2440a4dde37d747ded5403592")).to eql("507a5b8dfed0fc6fe8801743720cedec06aa5c6fca72b07c49964492fb98a714")
11
11
  end
12
12
  end
13
-
13
+
14
14
  describe "ripemd160(str)" do
15
15
  it "properly calculates ripemd160 hash" do
16
16
  expect(ripemd160("abc", ascii: true)).to eql("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")
17
17
  expect(ripemd160("e8026715af68676e0287ec9aa774f8103e4bddd5505b209263a8ff97c6ea29cc")).to eql("166db6510884918f31a9d246404760db8154bf84")
18
18
  end
19
19
  end
20
-
20
+
21
21
  describe "hmac_sha512_hex(key, message)" do
22
22
  it "properly calculates hmac sha512" do
23
23
  expect(hmac_sha512_hex("Jefe", "what do ya want for nothing?")).to eql("164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737")
24
24
  end
25
25
  end
26
-
26
+
27
27
  describe "hex_to_int" do
28
28
  it "converts hex to integer" do
29
29
  expect(hex_to_int("abcdef0123456789")).to eql(12379813738877118345)
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,2 @@
1
- require 'simplecov'
2
1
  require 'money-tree'
3
2
  require 'pry'
metadata CHANGED
@@ -1,156 +1,104 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money-tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Winkelspecht
8
- autorequire:
8
+ - Afri Schoedon
9
+ autorequire:
9
10
  bindir: bin
10
- cert_chain:
11
- - |
12
- -----BEGIN CERTIFICATE-----
13
- MIIEHDCCAoSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFtYXR0
14
- L0RDPWdlbS9EQz1jbzAeFw0xODA1MzAyMTQwNDZaFw0xOTA1MzAyMTQwNDZaMBwx
15
- GjAYBgNVBAMMEW1hdHQvREM9Z2VtL0RDPWNvMIIBojANBgkqhkiG9w0BAQEFAAOC
16
- AY8AMIIBigKCAYEAxfbjMHFlxA2P+4YWPagKoGAMi4078imgXdFbD3Rloe6cGfYp
17
- IMUQitiHrKi6fhSE0UjXmoP3qnYFddm1enN9zUAFRhHWv7xpINqSqss4PYAb5Anl
18
- RYZu3jromop5aVodi15HUfu5z27MvBm4rAaN/dDRfh/rT2hDbTTh0HmvEaPUDfX6
19
- TyflAttfabFvtY4qsD+ao8tks0DytqyuEWZ0tvQ6upOgHRNNuYDwDZB1T9v2dq2w
20
- 3goJFmOKBMMn7UH8WMjD3HiOuRD4tWhq5xWLjBqjzFlVPlZPgdCNyXeMMnLXER98
21
- NY35cVWFFuqG+kZwy4MFKdE9WFTocLZxLFo0VVTNSpPara9HirbHtIo9jZNuop4S
22
- g4JTf1F8dIWYii3sXoAYZfkl6rHVRP0G/OV5LcTfSS3QkmI5hNltz5FZzc+qI6S1
23
- rTR1ZwTy1rRI3coFY7vDRaFWBoMbbo/DytgCE3+rfbVDxQrJa4aZ0iYDhu8LXEA1
24
- VTtpf1EWYCOsYE1TAgMBAAGjaTBnMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0G
25
- A1UdDgQWBBQ6QoDNre7LFgOukH2Cv+RqZyfUzjAWBgNVHREEDzANgQttYXR0QGdl
26
- bS5jbzAWBgNVHRIEDzANgQttYXR0QGdlbS5jbzANBgkqhkiG9w0BAQsFAAOCAYEA
27
- kOxYnOsB+NwHwLc2lHEZ8ubxanq2qIZDhvVQ4M31gwmba43xO7vq0ktFxYRvozs4
28
- 74dQ6bmY2e7njoFgeutyJwxulA+BC71mDQA1s4WsZo7Z2TRgB0GViVqHrzq+jY+M
29
- p9mTHQqKH+2j0P9T4DXSzq4qOaBA3YROAwAzYI9N8MObeWkRt2pZ4zYQrAniP2nd
30
- wzXs/G5lWbbntVcvQOfAAXBipSJ3X5P2EGpUytP9ZpGdezY5HZzuiJFcmCf1CM3t
31
- VX4NZjbJak9gOY0AFD0Aw497sYenm0VBExclOmeRuZLffpWteTTL//utpG3bbFPl
32
- jQ78uzsrexYTYW5IshjfSIf3TZxm50Z45pyOTow5EOP1Nd7OmKOcI8hrLGv5+AlD
33
- hCnomUTUNsM4Rjwl5rzQiIn3ezv6+0tlg4rWJmVTuOGwcHk/oj1In2sPjCqm0pgx
34
- TLnMa8gr6aUpuHR5s2N4ZH0Q2YIsaD6cv7DYXt+G4MRut3njOYHfkqsSVykO6hvr
35
- -----END CERTIFICATE-----
36
- date: 2018-05-30 00:00:00.000000000 Z
11
+ cert_chain: []
12
+ date: 2022-11-03 00:00:00.000000000 Z
37
13
  dependencies:
38
14
  - !ruby/object:Gem::Dependency
39
- name: ffi
15
+ name: openssl
40
16
  requirement: !ruby/object:Gem::Requirement
41
17
  requirements:
42
18
  - - ">="
43
19
  - !ruby/object:Gem::Version
44
- version: '0'
20
+ version: '2.2'
45
21
  type: :runtime
46
22
  prerelease: false
47
23
  version_requirements: !ruby/object:Gem::Requirement
48
24
  requirements:
49
25
  - - ">="
50
26
  - !ruby/object:Gem::Version
51
- version: '0'
27
+ version: '2.2'
52
28
  - !ruby/object:Gem::Dependency
53
29
  name: bundler
54
30
  requirement: !ruby/object:Gem::Requirement
55
31
  requirements:
56
32
  - - "~>"
57
33
  - !ruby/object:Gem::Version
58
- version: '1.3'
34
+ version: '2.2'
59
35
  type: :development
60
36
  prerelease: false
61
37
  version_requirements: !ruby/object:Gem::Requirement
62
38
  requirements:
63
39
  - - "~>"
64
40
  - !ruby/object:Gem::Version
65
- version: '1.3'
41
+ version: '2.2'
66
42
  - !ruby/object:Gem::Dependency
67
43
  name: rake
68
44
  requirement: !ruby/object:Gem::Requirement
69
45
  requirements:
70
- - - ">="
46
+ - - "~>"
71
47
  - !ruby/object:Gem::Version
72
- version: '0'
48
+ version: '13.0'
73
49
  type: :development
74
50
  prerelease: false
75
51
  version_requirements: !ruby/object:Gem::Requirement
76
52
  requirements:
77
- - - ">="
53
+ - - "~>"
78
54
  - !ruby/object:Gem::Version
79
- version: '0'
55
+ version: '13.0'
80
56
  - !ruby/object:Gem::Dependency
81
57
  name: rspec
82
58
  requirement: !ruby/object:Gem::Requirement
83
59
  requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- version: '0'
87
- type: :development
88
- prerelease: false
89
- version_requirements: !ruby/object:Gem::Requirement
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
- - !ruby/object:Gem::Dependency
95
- name: simplecov
96
- requirement: !ruby/object:Gem::Requirement
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- version: '0'
101
- type: :development
102
- prerelease: false
103
- version_requirements: !ruby/object:Gem::Requirement
104
- requirements:
105
- - - ">="
106
- - !ruby/object:Gem::Version
107
- version: '0'
108
- - !ruby/object:Gem::Dependency
109
- name: coveralls
110
- requirement: !ruby/object:Gem::Requirement
111
- requirements:
112
- - - ">="
60
+ - - "~>"
113
61
  - !ruby/object:Gem::Version
114
- version: '0'
62
+ version: '3.10'
115
63
  type: :development
116
64
  prerelease: false
117
65
  version_requirements: !ruby/object:Gem::Requirement
118
66
  requirements:
119
- - - ">="
67
+ - - "~>"
120
68
  - !ruby/object:Gem::Version
121
- version: '0'
69
+ version: '3.10'
122
70
  - !ruby/object:Gem::Dependency
123
71
  name: pry
124
72
  requirement: !ruby/object:Gem::Requirement
125
73
  requirements:
126
- - - ">="
74
+ - - "~>"
127
75
  - !ruby/object:Gem::Version
128
- version: '0'
76
+ version: '0.4'
129
77
  type: :development
130
78
  prerelease: false
131
79
  version_requirements: !ruby/object:Gem::Requirement
132
80
  requirements:
133
- - - ">="
81
+ - - "~>"
134
82
  - !ruby/object:Gem::Version
135
- version: '0'
83
+ version: '0.4'
136
84
  description: A Ruby Gem implementation of Bitcoin HD Wallets
137
85
  email:
138
86
  - winkelspecht@gmail.com
87
+ - gems@q9f.cc
139
88
  executables: []
140
89
  extensions: []
141
90
  extra_rdoc_files: []
142
91
  files:
92
+ - ".github/donation_btc_qr_code.gif"
93
+ - ".github/workflows/spec.yml"
143
94
  - ".gitignore"
144
95
  - ".rspec"
145
- - ".simplecov"
146
- - ".travis.yml"
147
96
  - Gemfile
148
97
  - LICENSE.txt
149
98
  - README.md
150
99
  - Rakefile
151
100
  - certs/mattatgemco.pem
152
101
  - checksum/money-tree-0.9.0.gem.sha512
153
- - donation_btc_qr_code.gif
154
102
  - lib/money-tree.rb
155
103
  - lib/money-tree/address.rb
156
104
  - lib/money-tree/key.rb
@@ -171,7 +119,7 @@ homepage: https://github.com/gemhq/money-tree
171
119
  licenses:
172
120
  - MIT
173
121
  metadata: {}
174
- post_install_message:
122
+ post_install_message:
175
123
  rdoc_options: []
176
124
  require_paths:
177
125
  - lib
@@ -186,9 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
134
  - !ruby/object:Gem::Version
187
135
  version: '0'
188
136
  requirements: []
189
- rubyforge_project:
190
- rubygems_version: 2.7.7
191
- signing_key:
137
+ rubygems_version: 3.3.23
138
+ signing_key:
192
139
  specification_version: 4
193
140
  summary: Bitcoin Hierarchical Deterministic Wallets in Ruby! (Bitcoin standard BIP0032)
194
141
  test_files:
checksums.yaml.gz.sig DELETED
Binary file
data/.simplecov DELETED
@@ -1,7 +0,0 @@
1
- require 'coveralls'
2
-
3
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
4
- SimpleCov::Formatter::HTMLFormatter,
5
- Coveralls::SimpleCov::Formatter
6
- ])
7
- SimpleCov.start
data/.travis.yml DELETED
@@ -1,3 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.0.0
data.tar.gz.sig DELETED
Binary file
metadata.gz.sig DELETED
Binary file