money-tree 0.10.0 → 0.11.1
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 +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
|