money-tree 0.8.8 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/money-tree/key.rb +3 -0
- data/lib/money-tree/node.rb +8 -7
- data/lib/money-tree/version.rb +1 -1
- data/lib/openssl_extensions.rb +18 -3
- data/spec/lib/money-tree/address_spec.rb +16 -16
- data/spec/lib/money-tree/node_spec.rb +245 -229
- data/spec/lib/money-tree/openssl_extensions_spec.rb +23 -0
- data/spec/lib/money-tree/private_key_spec.rb +19 -19
- data/spec/lib/money-tree/public_key_spec.rb +30 -26
- data/spec/lib/money-tree/support_spec.rb +7 -7
- metadata +4 -2
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MoneyTree::OpenSSLExtensions do
|
4
|
+
include MoneyTree::OpenSSLExtensions
|
5
|
+
|
6
|
+
context "with inputs" do
|
7
|
+
let(:key1) { OpenSSL::PKey::EC.new("secp256k1").generate_key }
|
8
|
+
let(:key2) { OpenSSL::PKey::EC.new("secp256k1").generate_key }
|
9
|
+
let(:point_1) { key1.public_key }
|
10
|
+
let(:point_2) { key2.public_key }
|
11
|
+
let(:point_infinity) { key1.public_key.set_to_infinity! }
|
12
|
+
|
13
|
+
it "requires valid points" do
|
14
|
+
expect { MoneyTree::OpenSSLExtensions.add(0, 0) }.to raise_error(ArgumentError)
|
15
|
+
expect { MoneyTree::OpenSSLExtensions.add(nil, nil) }.to raise_error(ArgumentError)
|
16
|
+
expect { MoneyTree::OpenSSLExtensions.add(point_1, 0) }.to raise_error(ArgumentError)
|
17
|
+
expect { MoneyTree::OpenSSLExtensions.add(0, point_2) }.to raise_error(ArgumentError)
|
18
|
+
expect { MoneyTree::OpenSSLExtensions.add(point_infinity, point_2) }.to raise_error(ArgumentError)
|
19
|
+
expect { MoneyTree::OpenSSLExtensions.add(point_1, point_2) }.to_not raise_error
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -8,91 +8,91 @@ describe MoneyTree::PrivateKey do
|
|
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!
|
11
|
-
@key.to_hex.length.
|
11
|
+
expect(@key.to_hex.length).to eql(64)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "preserves leading zeros" do
|
15
15
|
master = MoneyTree::Master.new seed_hex: "9cf6b6e8451c7d551cb402e2997566e5c7c258543eadb184f9f39322b2e6959b"
|
16
|
-
master.node_for_path("m/427").private_key.to_hex.length.
|
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
|
-
@key.to_hex.
|
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
|
-
@key.to_wif.length.
|
26
|
+
expect(@key.to_wif.length).to eql(52)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "starts with K or L" do
|
30
|
-
%w(K L).
|
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
|
-
@key.to_wif.
|
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
|
-
@key.to_wif(compressed: false).length.
|
40
|
+
expect(@key.to_wif(compressed: false).length).to eql(51)
|
41
41
|
end
|
42
42
|
|
43
43
|
it "starts with 5" do
|
44
|
-
@key.to_wif(compressed: false)[0].
|
44
|
+
expect(@key.to_wif(compressed: false)[0]).to eql('5')
|
45
45
|
end
|
46
46
|
|
47
47
|
it "is valid" do
|
48
|
-
@key.to_wif(compressed: false).
|
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
|
-
@key.from_wif("5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ").
|
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
|
-
@key.to_base64.length.
|
64
|
+
expect(@key.to_base64.length).to eql(44)
|
65
65
|
end
|
66
66
|
|
67
67
|
it "is a valid base64" do
|
68
|
-
@key.to_base64.
|
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
|
-
@key.to_hex.
|
75
|
+
expect(@key.to_hex).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
|
76
76
|
end
|
77
77
|
|
78
78
|
it "returns the key from base64 encoding" do
|
79
|
-
@key.from_base64("Xq5Tdftfeg6mUFZjY776KDDvRBvcsZGYrfMY+u6G1ks=").
|
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
|
-
@key.valid
|
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)
|
96
96
|
|
97
97
|
end
|
98
98
|
end
|
@@ -104,7 +104,7 @@ describe MoneyTree::PrivateKey do
|
|
104
104
|
|
105
105
|
describe "to_wif" do
|
106
106
|
it "returns same wif" do
|
107
|
-
@key.to_wif.
|
107
|
+
expect(@key.to_wif).to eql('cRhes8SBnsF6WizphaRKQKZZfDniDa9Bxcw31yKeEC1KDExhxFgD')
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
@@ -10,47 +10,47 @@ describe MoneyTree::PublicKey do
|
|
10
10
|
|
11
11
|
describe "to_hex(compressed: false)" do
|
12
12
|
it "has 65 bytes" do
|
13
|
-
@key.uncompressed.to_hex.length.
|
13
|
+
expect(@key.uncompressed.to_hex.length).to eql(130)
|
14
14
|
end
|
15
15
|
|
16
16
|
it "is a valid hex" do
|
17
|
-
@key.uncompressed.to_hex.
|
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
|
-
@key.to_hex.length.
|
23
|
+
expect(@key.to_hex.length).to eql(66)
|
24
24
|
end
|
25
25
|
|
26
26
|
it "is a valid compressed hex" do
|
27
|
-
@key.to_hex.
|
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
|
-
@key.to_fingerprint.
|
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
|
-
@key.uncompressed.to_address.length.
|
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
|
-
@key.uncompressed.to_address.
|
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
|
-
@key.to_address.length.
|
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
|
-
@key.to_address.
|
53
|
+
expect(@key.to_address).to eql('13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe' )
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -62,63 +62,63 @@ describe MoneyTree::PublicKey do
|
|
62
62
|
|
63
63
|
describe "to_hex(compressed: false)" do
|
64
64
|
it "has 65 bytes" do
|
65
|
-
@key.uncompressed.to_hex.length.
|
65
|
+
expect(@key.uncompressed.to_hex.length).to eql(130)
|
66
66
|
end
|
67
67
|
|
68
68
|
it "is a valid hex" do
|
69
|
-
@key.uncompressed.to_hex.
|
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
|
-
@key.compressed.to_hex.length.
|
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
|
-
@key.compressed.to_hex.
|
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
|
-
@key.compressed.to_fingerprint.
|
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
|
-
@key.uncompressed.to_address.length.
|
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
|
-
@key.uncompressed.to_address.
|
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
|
-
@key.compressed.to_address.length.
|
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
|
-
@key.compressed.to_address.
|
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
|
112
|
-
@key.compression.
|
112
|
+
expect(@key.compression).to eql(:uncompressed)
|
113
113
|
@key.compression = :compressed
|
114
|
-
@key.compression.
|
114
|
+
expect(@key.compression).to eql(:compressed)
|
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)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -128,7 +128,7 @@ describe MoneyTree::PublicKey do
|
|
128
128
|
100.times do
|
129
129
|
results << MoneyTree::PublicKey.new('042dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b11203096f1a1c5276a73f91b9465357004c2103cc42c63d6d330df589080d2e4').to_s
|
130
130
|
end
|
131
|
-
results.uniq.length.
|
131
|
+
expect(results.uniq.length).to eql(1)
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
@@ -141,7 +141,7 @@ describe MoneyTree::PublicKey do
|
|
141
141
|
before_str = @key.to_s
|
142
142
|
@key.uncompressed
|
143
143
|
after_str = @key.to_s
|
144
|
-
before_str.
|
144
|
+
expect(before_str).to eql(after_str)
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
@@ -154,7 +154,7 @@ describe MoneyTree::PublicKey do
|
|
154
154
|
before_str = @key.to_s
|
155
155
|
@key.compressed
|
156
156
|
after_str = @key.to_s
|
157
|
-
before_str.
|
157
|
+
expect(before_str).to eql(after_str)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
@@ -166,7 +166,11 @@ describe MoneyTree::PublicKey do
|
|
166
166
|
end
|
167
167
|
|
168
168
|
it "should have an address starting with m or n" do
|
169
|
-
%w(m n).
|
169
|
+
expect(%w(m n)).to include(@key.to_s[0])
|
170
|
+
end
|
171
|
+
|
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])
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
@@ -176,7 +180,7 @@ describe MoneyTree::PublicKey do
|
|
176
180
|
end
|
177
181
|
|
178
182
|
it "should have an address starting with m or n" do
|
179
|
-
%w(m n).
|
183
|
+
expect(%w(m n)).to include(@key.to_s[0])
|
180
184
|
end
|
181
185
|
end
|
182
186
|
end
|
@@ -5,28 +5,28 @@ describe MoneyTree::Support do
|
|
5
5
|
|
6
6
|
describe "sha256(str)" do
|
7
7
|
it "properly calculates sha256 hash" do
|
8
|
-
sha256("abc", ascii: true).
|
9
|
-
sha256("800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d").
|
10
|
-
sha256("8147786c4d15106333bf278d71dadaf1079ef2d2440a4dde37d747ded5403592").
|
8
|
+
expect(sha256("abc", ascii: true)).to eql("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
|
9
|
+
expect(sha256("800c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d")).to eql("8147786c4d15106333bf278d71dadaf1079ef2d2440a4dde37d747ded5403592")
|
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
|
-
ripemd160("abc", ascii: true).
|
17
|
-
ripemd160("e8026715af68676e0287ec9aa774f8103e4bddd5505b209263a8ff97c6ea29cc").
|
16
|
+
expect(ripemd160("abc", ascii: true)).to eql("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")
|
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
|
-
hmac_sha512_hex("Jefe", "what do ya want for nothing?").
|
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
|
-
hex_to_int("abcdef0123456789").
|
29
|
+
expect(hex_to_int("abcdef0123456789")).to eql(12379813738877118345)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: money-tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Micah Winkelspecht
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- money-tree.gemspec
|
136
136
|
- spec/lib/money-tree/address_spec.rb
|
137
137
|
- spec/lib/money-tree/node_spec.rb
|
138
|
+
- spec/lib/money-tree/openssl_extensions_spec.rb
|
138
139
|
- spec/lib/money-tree/private_key_spec.rb
|
139
140
|
- spec/lib/money-tree/public_key_spec.rb
|
140
141
|
- spec/lib/money-tree/support_spec.rb
|
@@ -166,6 +167,7 @@ summary: Bitcoin Hierarchical Deterministic Wallets in Ruby! (Bitcoin standard B
|
|
166
167
|
test_files:
|
167
168
|
- spec/lib/money-tree/address_spec.rb
|
168
169
|
- spec/lib/money-tree/node_spec.rb
|
170
|
+
- spec/lib/money-tree/openssl_extensions_spec.rb
|
169
171
|
- spec/lib/money-tree/private_key_spec.rb
|
170
172
|
- spec/lib/money-tree/public_key_spec.rb
|
171
173
|
- spec/lib/money-tree/support_spec.rb
|