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 +4 -4
- data/{donation_btc_qr_code.gif → .github/donation_btc_qr_code.gif} +0 -0
- data/.github/workflows/spec.yml +31 -0
- data/README.md +14 -4
- data/Rakefile +1 -1
- data/lib/money-tree/address.rb +2 -2
- data/lib/money-tree/node.rb +6 -1
- data/lib/money-tree/support.rb +17 -17
- data/lib/money-tree/version.rb +1 -1
- data/lib/money-tree.rb +0 -1
- data/lib/openssl_extensions.rb +7 -52
- data/money-tree.gemspec +8 -19
- data/spec/lib/money-tree/address_spec.rb +23 -7
- data/spec/lib/money-tree/openssl_extensions_spec.rb +49 -1
- data/spec/lib/money-tree/private_key_spec.rb +20 -20
- data/spec/lib/money-tree/public_key_spec.rb +43 -31
- data/spec/lib/money-tree/support_spec.rb +3 -3
- data/spec/spec_helper.rb +0 -1
- metadata +28 -81
- checksums.yaml.gz.sig +0 -0
- data/.simplecov +0 -7
- data/.travis.yml +0 -3
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 040b86e807e6dea0ebf4dfc4b5e508e3f9ef673c94b95a210a18c125d8857974
|
4
|
+
data.tar.gz: '01800e0fb32058488fd01f1a8f2be3539788c7d0bebc0021fd49776fdde947a4'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70a6465799b1f7140a2e45c2ded416b41e4b64a7801b57325ed20cea470c92cad96e7644596d523a192254e7284eb772406e90af0a797f5b367304cbe2e9b725
|
7
|
+
data.tar.gz: 2d0c6bea3a33f161cf30a3400d3f75b6119098f035eca6cdac076c11c03596a2e0e205456b1e3ea2453f2ad1e58fd7edec91ff21ec1a8fd515c2d7836169762c
|
File without changes
|
@@ -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](
|
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
data/lib/money-tree/address.rb
CHANGED
@@ -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
|
data/lib/money-tree/node.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/money-tree/support.rb
CHANGED
@@ -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
|
data/lib/money-tree/version.rb
CHANGED
data/lib/money-tree.rb
CHANGED
data/lib/openssl_extensions.rb
CHANGED
@@ -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
|
-
|
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 =
|
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 =
|
33
|
-
|
34
|
-
sum_point
|
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
|
-
|
31
|
-
|
32
|
-
spec.add_development_dependency "
|
33
|
-
spec.add_development_dependency "
|
34
|
-
spec.add_development_dependency "
|
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
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.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Micah Winkelspecht
|
8
|
-
|
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:
|
15
|
+
name: openssl
|
40
16
|
requirement: !ruby/object:Gem::Requirement
|
41
17
|
requirements:
|
42
18
|
- - ">="
|
43
19
|
- !ruby/object:Gem::Version
|
44
|
-
version: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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
|
-
|
190
|
-
|
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
data/.travis.yml
DELETED
data.tar.gz.sig
DELETED
Binary file
|
metadata.gz.sig
DELETED
Binary file
|