money-tree 0.10.0 → 0.11.1
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/{donation_btc_qr_code.gif → .github/donation_btc_qr_code.gif} +0 -0
- data/.github/workflows/spec.yml +33 -0
- data/Gemfile +15 -3
- data/README.md +14 -4
- data/Rakefile +2 -2
- data/checksum/money-tree-0.11.0.gem.sha512 +1 -0
- data/checksum/money-tree-0.9.0.gem.sha512 +1 -1
- data/lib/money-tree/address.rb +16 -6
- data/lib/money-tree/key.rb +32 -25
- data/lib/money-tree/networks.rb +16 -15
- data/lib/money-tree/node.rb +49 -39
- data/lib/money-tree/support.rb +59 -34
- data/lib/money-tree/version.rb +1 -1
- data/lib/money-tree.rb +6 -7
- data/lib/openssl_extensions.rb +11 -54
- data/money-tree.gemspec +22 -30
- data/spec/{lib/money-tree → money-tree}/address_spec.rb +42 -8
- data/spec/money-tree/money_tree_spec.rb +9 -0
- data/spec/{lib/money-tree → money-tree}/node_spec.rb +425 -15
- data/spec/money-tree/openssl_extensions_spec.rb +71 -0
- data/spec/{lib/money-tree → money-tree}/private_key_spec.rb +27 -27
- data/spec/{lib/money-tree → money-tree}/public_key_spec.rb +81 -40
- data/spec/{lib/money-tree → money-tree}/support_spec.rb +4 -4
- data/spec/spec_helper.rb +15 -3
- metadata +37 -150
- checksums.yaml.gz.sig +0 -0
- data/.simplecov +0 -7
- data/.travis.yml +0 -3
- data/spec/lib/money-tree/openssl_extensions_spec.rb +0 -23
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
data/lib/money-tree/support.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "base64"
|
2
|
+
require "bech32"
|
3
|
+
require "openssl"
|
3
4
|
|
4
5
|
module MoneyTree
|
5
6
|
module Support
|
6
7
|
include OpenSSL
|
7
|
-
|
8
|
+
extend self
|
9
|
+
|
8
10
|
INT32_MAX = 256 ** [1].pack("L*").size
|
9
11
|
INT64_MAX = 256 ** [1].pack("Q*").size
|
10
12
|
BASE58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
11
|
-
|
12
|
-
def int_to_base58(int_val, leading_zero_bytes=0)
|
13
|
-
base58_val, base =
|
13
|
+
|
14
|
+
def int_to_base58(int_val, leading_zero_bytes = 0)
|
15
|
+
base58_val, base = "", BASE58_CHARS.size
|
14
16
|
while int_val > 0
|
15
17
|
int_val, remainder = int_val.divmod(base)
|
16
18
|
base58_val = BASE58_CHARS[remainder] + base58_val
|
@@ -20,27 +22,28 @@ module MoneyTree
|
|
20
22
|
|
21
23
|
def base58_to_int(base58_val)
|
22
24
|
int_val, base = 0, BASE58_CHARS.size
|
23
|
-
base58_val.reverse.each_char.with_index do |char,index|
|
24
|
-
raise ArgumentError,
|
25
|
-
int_val += char_index*(base**index)
|
25
|
+
base58_val.reverse.each_char.with_index do |char, index|
|
26
|
+
raise ArgumentError, "Value not a valid Base58 String." unless char_index = BASE58_CHARS.index(char)
|
27
|
+
int_val += char_index * (base ** index)
|
26
28
|
end
|
27
29
|
int_val
|
28
30
|
end
|
29
31
|
|
30
32
|
def encode_base58(hex)
|
31
|
-
leading_zero_bytes
|
32
|
-
("1"*leading_zero_bytes) + int_to_base58(
|
33
|
+
leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : "").size / 2
|
34
|
+
("1" * leading_zero_bytes) + int_to_base58(hex.to_i(16))
|
33
35
|
end
|
34
36
|
|
35
37
|
def decode_base58(base58_val)
|
36
|
-
s = base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ?
|
37
|
-
s =
|
38
|
-
leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 :
|
39
|
-
s = ("00"*leading_zero_bytes) + s
|
38
|
+
s = base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? "0" + s : s)
|
39
|
+
s = "" if s == "00"
|
40
|
+
leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : "").size
|
41
|
+
s = ("00" * leading_zero_bytes) + s if leading_zero_bytes > 0
|
40
42
|
s
|
41
43
|
end
|
44
|
+
|
42
45
|
alias_method :base58_to_hex, :decode_base58
|
43
|
-
|
46
|
+
|
44
47
|
def to_serialized_base58(hex)
|
45
48
|
hash = sha256 hex
|
46
49
|
hash = sha256 hash
|
@@ -48,7 +51,14 @@ module MoneyTree
|
|
48
51
|
address = hex + checksum
|
49
52
|
encode_base58 address
|
50
53
|
end
|
51
|
-
|
54
|
+
|
55
|
+
def to_serialized_bech32(human_readable_part, hex)
|
56
|
+
segwit_addr = Bech32::SegwitAddr.new
|
57
|
+
segwit_addr.hrp = human_readable_part
|
58
|
+
segwit_addr.script_pubkey = "0000" + hex
|
59
|
+
segwit_addr.addr
|
60
|
+
end
|
61
|
+
|
52
62
|
def from_serialized_base58(base58)
|
53
63
|
hex = decode_base58 base58
|
54
64
|
checksum = hex.slice!(-8..-1)
|
@@ -56,46 +66,46 @@ module MoneyTree
|
|
56
66
|
raise EncodingError unless checksum == compare_checksum
|
57
67
|
hex
|
58
68
|
end
|
59
|
-
|
69
|
+
|
60
70
|
def digestify(digest_type, source, opts = {})
|
61
71
|
source = [source].pack("H*") unless opts[:ascii]
|
62
72
|
bytes_to_hex Digest.digest(digest_type, source)
|
63
73
|
end
|
64
|
-
|
74
|
+
|
65
75
|
def sha256(source, opts = {})
|
66
|
-
digestify(
|
76
|
+
digestify("SHA256", source, opts)
|
67
77
|
end
|
68
|
-
|
78
|
+
|
69
79
|
def ripemd160(source, opts = {})
|
70
|
-
digestify(
|
80
|
+
digestify("RIPEMD160", source, opts)
|
71
81
|
end
|
72
|
-
|
82
|
+
|
73
83
|
def encode_base64(hex)
|
74
84
|
Base64.encode64([hex].pack("H*")).chomp
|
75
85
|
end
|
76
|
-
|
86
|
+
|
77
87
|
def decode_base64(base64)
|
78
88
|
Base64.decode64(base64).unpack("H*")[0]
|
79
89
|
end
|
80
|
-
|
90
|
+
|
81
91
|
def hmac_sha512(key, message)
|
82
92
|
digest = Digest::SHA512.new
|
83
93
|
HMAC.digest digest, key, message
|
84
94
|
end
|
85
|
-
|
95
|
+
|
86
96
|
def hmac_sha512_hex(key, message)
|
87
97
|
md = hmac_sha512(key, message)
|
88
|
-
md.unpack("H*").first.rjust(64,
|
98
|
+
md.unpack("H*").first.rjust(64, "0")
|
89
99
|
end
|
90
|
-
|
100
|
+
|
91
101
|
def bytes_to_int(bytes, base = 16)
|
92
102
|
if bytes.is_a?(Array)
|
93
103
|
bytes = bytes.pack("C*")
|
94
104
|
end
|
95
105
|
bytes.unpack("H*")[0].to_i(16)
|
96
106
|
end
|
97
|
-
|
98
|
-
def int_to_hex(i, size=nil)
|
107
|
+
|
108
|
+
def int_to_hex(i, size = nil)
|
99
109
|
hex = i.to_s(16).downcase
|
100
110
|
if (hex.size % 2) != 0
|
101
111
|
hex = "#{0}#{hex}"
|
@@ -107,21 +117,36 @@ module MoneyTree
|
|
107
117
|
hex
|
108
118
|
end
|
109
119
|
end
|
110
|
-
|
120
|
+
|
111
121
|
def int_to_bytes(i)
|
112
122
|
[int_to_hex(i)].pack("H*")
|
113
123
|
end
|
114
|
-
|
124
|
+
|
115
125
|
def bytes_to_hex(bytes)
|
116
126
|
bytes.unpack("H*")[0].downcase
|
117
127
|
end
|
118
|
-
|
128
|
+
|
119
129
|
def hex_to_bytes(hex)
|
120
130
|
[hex].pack("H*")
|
121
131
|
end
|
122
|
-
|
132
|
+
|
123
133
|
def hex_to_int(hex)
|
124
134
|
hex.to_i(16)
|
125
135
|
end
|
136
|
+
|
137
|
+
def encode_p2wpkh_p2sh(value)
|
138
|
+
chk = [Digest::SHA256.hexdigest(Digest::SHA256.digest(value))].pack("H*")[0...4]
|
139
|
+
encode_base58 (value + chk).unpack("H*")[0]
|
140
|
+
end
|
141
|
+
|
142
|
+
def custom_hash_160(value)
|
143
|
+
[OpenSSL::Digest::RIPEMD160.hexdigest(Digest::SHA256.digest(value))].pack("H*")
|
144
|
+
end
|
145
|
+
|
146
|
+
def convert_p2wpkh_p2sh(key_hex, prefix)
|
147
|
+
push_20 = ["0014"].pack("H*")
|
148
|
+
script_sig = push_20 + custom_hash_160([key_hex].pack("H*"))
|
149
|
+
encode_p2wpkh_p2sh(prefix + custom_hash_160(script_sig))
|
150
|
+
end
|
126
151
|
end
|
127
152
|
end
|
data/lib/money-tree/version.rb
CHANGED
data/lib/money-tree.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
require "openssl_extensions"
|
2
|
-
require "money-tree/version"
|
3
1
|
require "money-tree/support"
|
4
|
-
|
5
|
-
require "money-tree/key"
|
2
|
+
|
6
3
|
require "money-tree/address"
|
4
|
+
require "money-tree/key"
|
7
5
|
require "money-tree/networks"
|
8
6
|
require "money-tree/node"
|
7
|
+
require "money-tree/version"
|
8
|
+
|
9
|
+
require "openssl_extensions"
|
9
10
|
|
10
|
-
module MoneyTree
|
11
|
-
|
12
|
-
end
|
11
|
+
module MoneyTree; end
|
data/lib/openssl_extensions.rb
CHANGED
@@ -1,73 +1,30 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'ffi'
|
3
|
+
require "openssl"
|
5
4
|
|
6
5
|
module MoneyTree
|
7
6
|
module OpenSSLExtensions
|
8
|
-
extend
|
9
|
-
ffi_lib ['libssl.so.1.0.0', 'libssl.so.10', 'libssl1.0.0', 'ssl']
|
7
|
+
extend self
|
10
8
|
|
11
|
-
|
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
|
-
def self.add(point_0, point_1)
|
9
|
+
def add(point_0, point_1)
|
25
10
|
validate_points(point_0, point_1)
|
26
|
-
|
27
|
-
group = EC_KEY_get0_group(eckey)
|
28
|
-
|
11
|
+
group = OpenSSL::PKey::EC::Group.new("secp256k1")
|
29
12
|
point_0_hex = point_0.to_bn.to_s(16)
|
30
|
-
point_0_pt =
|
13
|
+
point_0_pt = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(point_0_hex, 16))
|
31
14
|
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
|
15
|
+
point_1_pt = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(point_1_hex, 16))
|
16
|
+
sum_point = point_0_pt.add(point_1_pt)
|
17
|
+
sum_point.to_bn.to_s(16)
|
50
18
|
end
|
51
19
|
|
52
|
-
def
|
20
|
+
def validate_points(*points)
|
53
21
|
points.each do |point|
|
54
22
|
if !point.is_a?(OpenSSL::PKey::EC::Point)
|
55
|
-
raise ArgumentError, "point must be an OpenSSL::PKey::EC::Point object"
|
23
|
+
raise ArgumentError, "point must be an OpenSSL::PKey::EC::Point object"
|
56
24
|
elsif point.infinity?
|
57
|
-
raise ArgumentError, "point must not be infinity"
|
25
|
+
raise ArgumentError, "point must not be infinity"
|
58
26
|
end
|
59
27
|
end
|
60
28
|
end
|
61
29
|
end
|
62
30
|
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
@@ -1,38 +1,30 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "money-tree/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
11
|
-
spec.description
|
12
|
-
spec.summary
|
13
|
-
spec.homepage
|
14
|
-
spec.license
|
7
|
+
spec.name = "money-tree"
|
8
|
+
spec.version = MoneyTree::VERSION
|
9
|
+
spec.authors = ["Micah Winkelspecht", "Afri Schoedon"]
|
10
|
+
spec.email = ["winkelspecht@gmail.com", "gems@q9f.cc"]
|
11
|
+
spec.description = %q{A Ruby Gem implementation of Bitcoin HD Wallets}
|
12
|
+
spec.summary = %q{Bitcoin Hierarchical Deterministic Wallets in Ruby! (Bitcoin standard BIP0032)}
|
13
|
+
spec.homepage = "https://github.com/GemHQ/money-tree"
|
14
|
+
spec.license = "MIT"
|
15
15
|
|
16
|
-
spec.files
|
17
|
-
spec.executables
|
18
|
-
spec.test_files
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
spec.
|
37
|
-
spec.
|
21
|
+
spec.metadata = {
|
22
|
+
"homepage_uri" => "https://github.com/GemHQ/money-tree",
|
23
|
+
"source_code_uri" => "https://github.com/GemHQ/money-tree",
|
24
|
+
"github_repo" => "https://github.com/GemHQ/money-tree",
|
25
|
+
"bug_tracker_uri" => "https://github.com/GemHQ/money-tree/issues",
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
spec.platform = Gem::Platform::RUBY
|
29
|
+
spec.required_ruby_version = ">= 2.6", "< 4.0"
|
38
30
|
end
|
@@ -1,17 +1,23 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
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")
|
@@ -19,37 +25,65 @@ describe MoneyTree::Address do
|
|
19
25
|
expect(address.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
|
20
26
|
expect(address.private_key.to_s).to eql("KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK")
|
21
27
|
expect(address.public_key.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
|
28
|
+
expect(address.to_p2wpkh_p2sh).to eql("31vNN7WVDxjvc5XZVKW3qV4B3nFLxsRPnE")
|
29
|
+
expect(address.to_bech32).to eql("bc1qrlwlgt5d0sdtq882qvk3jc0sywucn76fwcmqma")
|
22
30
|
end
|
23
|
-
|
31
|
+
|
24
32
|
it "imports a private key in compressed wif format" do
|
25
33
|
address = MoneyTree::Address.new private_key: "KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK"
|
26
34
|
expect(address.private_key.key).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
|
27
35
|
expect(address.public_key.key).to eql("022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b")
|
28
36
|
expect(address.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
|
37
|
+
expect(address.to_p2wpkh_p2sh).to eql("31vNN7WVDxjvc5XZVKW3qV4B3nFLxsRPnE")
|
38
|
+
expect(address.to_bech32).to eql("bc1qrlwlgt5d0sdtq882qvk3jc0sywucn76fwcmqma")
|
29
39
|
end
|
30
|
-
|
40
|
+
|
31
41
|
it "imports a private key in uncompressed wif format" do
|
32
42
|
address = MoneyTree::Address.new private_key: "5JXz5ZyFk31oHVTQxqce7yitCmTAPxBqeGQ4b7H3Aj3L45wUhoa"
|
33
43
|
expect(address.private_key.key).to eql("5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b")
|
34
44
|
expect(address.public_key.key).to eql("022dfc2557a007c93092c2915f11e8aa70c4f399a6753e2e908330014091580e4b")
|
35
45
|
end
|
36
46
|
end
|
37
|
-
|
47
|
+
|
38
48
|
describe "to_s" do
|
39
49
|
before do
|
40
50
|
@address = MoneyTree::Address.new private_key: "5eae5375fb5f7a0ea650566363befa2830ef441bdcb19198adf318faee86d64b"
|
41
51
|
end
|
42
|
-
|
52
|
+
|
43
53
|
it "returns compressed base58 public key" do
|
44
54
|
expect(@address.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
|
45
55
|
expect(@address.public_key.to_s).to eql("13uVqa35BMo4mYq9LiZrXVzoz9EFZ6aoXe")
|
56
|
+
expect(@address.to_p2wpkh_p2sh).to eql("31vNN7WVDxjvc5XZVKW3qV4B3nFLxsRPnE")
|
57
|
+
expect(@address.to_bech32).to eql("bc1qrlwlgt5d0sdtq882qvk3jc0sywucn76fwcmqma")
|
46
58
|
end
|
47
|
-
|
59
|
+
|
48
60
|
it "returns compressed WIF private key" do
|
49
61
|
expect(@address.private_key.to_s).to eql("KzPkwAXJ4wtXHnbamTaJqoMrzwCUUJaqhUxnqYhnZvZH6KhgmDPK")
|
50
62
|
end
|
51
63
|
end
|
52
64
|
|
65
|
+
context "bitcoin wiki" do
|
66
|
+
# ref https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
|
67
|
+
subject(:wiki_v1) { MoneyTree::Address.new private_key: "18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725" }
|
68
|
+
|
69
|
+
it "always regenerates the bitcoin wiki v1 example" do
|
70
|
+
expect(wiki_v1.public_key.key).to eq "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
|
71
|
+
expect(wiki_v1.to_s).to eq "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
|
72
|
+
expect(wiki_v1.to_p2wpkh_p2sh).to eql("3BxwGNjvG4CP14tAZodgYyZ7UTjruYDyAM")
|
73
|
+
expect(wiki_v1.to_bech32).to eql("bc1q7499s50fxu4c0qg23esvm5h8elvqkm33r2tdza")
|
74
|
+
end
|
75
|
+
|
76
|
+
# ref https://en.bitcoin.it/wiki/Bech32
|
77
|
+
subject(:wiki_bech32) { MoneyTree::Address.new private_key: "0000000000000000000000000000000000000000000000000000000000000001" }
|
78
|
+
|
79
|
+
it "always regenerates the bitcoin wiki v1 example" do
|
80
|
+
expect(wiki_bech32.public_key.key).to eq "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
|
81
|
+
expect(wiki_bech32.to_s).to eq "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH"
|
82
|
+
expect(wiki_bech32.to_p2wpkh_p2sh).to eql("3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN")
|
83
|
+
expect(wiki_bech32.to_bech32).to eql("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
53
87
|
context "testnet3" do
|
54
88
|
before do
|
55
89
|
@address = MoneyTree::Address.new network: :bitcoin_testnet
|