cash-addr 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +35 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +53 -0
- data/LICENSE.txt +13 -0
- data/README.md +73 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +6 -0
- data/cash-addr.gemspec +31 -0
- data/circle.yml +7 -0
- data/doc/CashAddr.html +110 -0
- data/doc/CashAddr/Converter.html +277 -0
- data/doc/CashAddr/InvalidAddress.html +103 -0
- data/doc/LICENSE_txt.html +99 -0
- data/doc/README_md.html +175 -0
- data/doc/cash-addr_gemspec.html +125 -0
- data/doc/created.rid +11 -0
- data/doc/css/fonts.css +167 -0
- data/doc/css/rdoc.css +590 -0
- data/doc/fonts/Lato-Light.ttf +0 -0
- data/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/doc/fonts/Lato-Regular.ttf +0 -0
- data/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +175 -0
- data/doc/js/darkfish.js +161 -0
- data/doc/js/jquery.js +4 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search.js +109 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js +229 -0
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +94 -0
- data/lib/cash_addr.rb +59 -0
- data/lib/cash_addr/address.rb +109 -0
- data/lib/cash_addr/crypto.rb +95 -0
- data/lib/cash_addr/version.rb +7 -0
- metadata +182 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base58'
|
4
|
+
require 'digest'
|
5
|
+
|
6
|
+
module CashAddr
|
7
|
+
class Address
|
8
|
+
attr_accessor :version, :payload, :prefix, :digest
|
9
|
+
|
10
|
+
VERSION_MAP = {
|
11
|
+
'legacy' => [
|
12
|
+
['P2SH', 5],
|
13
|
+
['P2PKH', 0],
|
14
|
+
['P2SHTestnet', 196],
|
15
|
+
['P2PKHTestnet', 111]
|
16
|
+
],
|
17
|
+
'cash' => [
|
18
|
+
['P2SH', 8],
|
19
|
+
['P2PKH', 0],
|
20
|
+
['P2SHTestnet', 8],
|
21
|
+
['P2PKHTestnet', 0]
|
22
|
+
]
|
23
|
+
}.freeze
|
24
|
+
DEFAULT_PREFIX = 'bitcoincash'
|
25
|
+
|
26
|
+
def initialize(version, payload, prefix = nil, digest = nil)
|
27
|
+
@version = version
|
28
|
+
@payload = payload
|
29
|
+
@digest = digest
|
30
|
+
|
31
|
+
@prefix = prefix ? prefix : DEFAULT_PREFIX
|
32
|
+
|
33
|
+
@version = 'P2SHTestnet' if prefix == 'bchtest' && version == 'P2SH'
|
34
|
+
@version = 'P2PKHTestnet' if prefix == 'bchtest' && version == 'P2PKH'
|
35
|
+
@prefix = 'bchtest' if %w[P2SHTestnet P2PKHTestnet].include?(@version)
|
36
|
+
end
|
37
|
+
|
38
|
+
def legacy_address
|
39
|
+
version_int = self.class.address_type('legacy', version)[1]
|
40
|
+
input = self.class.code_list_to_string([version_int] + payload + Array(digest))
|
41
|
+
input += Digest::SHA256.digest(Digest::SHA256.digest(input))[0..3] unless digest
|
42
|
+
Base58.binary_to_base58(input, :bitcoin)
|
43
|
+
end
|
44
|
+
|
45
|
+
def cash_address
|
46
|
+
version_int = self.class.address_type('cash', version)[1]
|
47
|
+
p = [version_int] + payload
|
48
|
+
p = CashAddr::Crypto.convertbits(p, 8, 5)
|
49
|
+
checksum = CashAddr::Crypto.calculate_checksum(prefix, p)
|
50
|
+
prefix + ':' + CashAddr::Crypto.b32encode(p + checksum)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.code_list_to_string(code_list)
|
54
|
+
code_list.map { |i| Array(i).pack('C*') }.flatten.join
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.address_type(address_type, version)
|
58
|
+
VERSION_MAP[address_type].each do |mapping|
|
59
|
+
return mapping if mapping.include?(version)
|
60
|
+
end
|
61
|
+
|
62
|
+
raise(CashAddr::InvalidAddress.new, 'Could not determine address version')
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.from_string(address_string)
|
66
|
+
raise(CashAddr::InvalidAddress, 'Expected string as input') unless address_string.is_a?(String)
|
67
|
+
return legacy_string(address_string) unless address_string.include?(':')
|
68
|
+
cash_string(address_string)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.legacy_string(address_string)
|
72
|
+
decoded = nil
|
73
|
+
begin
|
74
|
+
decoded = Base58.base58_to_binary(address_string, :bitcoin).bytes
|
75
|
+
rescue StandardError
|
76
|
+
raise(CashAddr::InvalidAddress.new, 'Could not decode legacy address')
|
77
|
+
end
|
78
|
+
ver = address_type('legacy', decoded[0].to_i)[0]
|
79
|
+
payload = decoded[1..-5]
|
80
|
+
digest = decoded[-4..-1]
|
81
|
+
|
82
|
+
new(ver, payload, nil, digest)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.cash_string(address_string)
|
86
|
+
if address_string.upcase != address_string && address_string.downcase != address_string
|
87
|
+
raise(CashAddr::InvalidAddress.new, 'Cash address contains uppercase and lowercase characters')
|
88
|
+
end
|
89
|
+
|
90
|
+
address_string = address_string.downcase
|
91
|
+
if !address_string.include?(':')
|
92
|
+
address_string = DEFAULT_PREFIX + ':' + address_string
|
93
|
+
end
|
94
|
+
|
95
|
+
pre, base32string = address_string.split(':')
|
96
|
+
decoded = CashAddr::Crypto.b32decode(base32string)
|
97
|
+
|
98
|
+
if !CashAddr::Crypto.verify_checksum(pre, decoded)
|
99
|
+
raise(CashAddr::InvalidAddress.new, 'Bad cash address checksum')
|
100
|
+
end
|
101
|
+
|
102
|
+
converted = CashAddr::Crypto.convertbits(decoded, 5, 8)
|
103
|
+
ver = CashAddr::Address.address_type('cash', converted[0].to_i)[0]
|
104
|
+
p = converted[1..-7]
|
105
|
+
|
106
|
+
new(ver, p, pre, nil)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CashAddr
|
4
|
+
class Crypto
|
5
|
+
CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
|
6
|
+
|
7
|
+
def self.polymod(values)
|
8
|
+
chk = 1
|
9
|
+
generator = [
|
10
|
+
[0x01, 0x98f2bc8e61],
|
11
|
+
[0x02, 0x79b76d99e2],
|
12
|
+
[0x04, 0xf33e5fb3c4],
|
13
|
+
[0x08, 0xae2eabe2a8],
|
14
|
+
[0x10, 0x1e4f43e470]
|
15
|
+
]
|
16
|
+
values.each do |value|
|
17
|
+
top = chk >> 35
|
18
|
+
chk = ((chk & 0x07ffffffff) << 5) ^ value
|
19
|
+
generator.each do |i|
|
20
|
+
chk ^= i[1] if (top & i[0]) != 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
chk ^ 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.prefix_expand(prefix)
|
27
|
+
val = if prefix
|
28
|
+
prefix.split('').map do |i|
|
29
|
+
i.ord & 0x1f
|
30
|
+
end
|
31
|
+
else
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
|
35
|
+
val + [0]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.calculate_checksum(prefix, payload)
|
39
|
+
poly = polymod(prefix_expand(prefix) + payload + [0, 0, 0, 0, 0, 0, 0, 0])
|
40
|
+
out = []
|
41
|
+
8.times do |i|
|
42
|
+
out.push((poly >> 5 * (7 - i)) & 0x1f)
|
43
|
+
end
|
44
|
+
out
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.verify_checksum(prefix, payload)
|
48
|
+
polymod(prefix_expand(prefix) + payload) == 0
|
49
|
+
rescue TypeError
|
50
|
+
raise CashAddr::InvalidAddress
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.b32decode(inputs)
|
54
|
+
out = []
|
55
|
+
return out unless inputs
|
56
|
+
|
57
|
+
inputs.split('').each do |letter|
|
58
|
+
out.push(CHARSET.index(letter))
|
59
|
+
end
|
60
|
+
out
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.b32encode(inputs)
|
64
|
+
out = ''
|
65
|
+
inputs.each do |char_code|
|
66
|
+
out += CHARSET[char_code].to_s
|
67
|
+
end
|
68
|
+
out
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.convertbits(data, frombits, tobits, pad = true)
|
72
|
+
acc = 0
|
73
|
+
bits = 0
|
74
|
+
ret = []
|
75
|
+
maxv = (1 << tobits) - 1
|
76
|
+
max_acc = (1 << (frombits + tobits - 1)) - 1
|
77
|
+
data.each do |value|
|
78
|
+
return nil if value < 0 || ((value >> frombits) != 0)
|
79
|
+
|
80
|
+
acc = ((acc << frombits) | value) & max_acc
|
81
|
+
bits += frombits
|
82
|
+
while bits >= tobits
|
83
|
+
bits -= tobits
|
84
|
+
ret.push((acc >> bits) & maxv)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
if pad
|
88
|
+
ret.push((acc << (tobits - bits)) & maxv) if bits != 0
|
89
|
+
elsif bits >= frombits || (((acc << (tobits - bits)) & maxv) != 0)
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
ret
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cash-addr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Ellithorpe
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.52.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.52.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: base58
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.2
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- josh.ellithorpe@coinbase.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".rubocop.yml"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- Gemfile.lock
|
96
|
+
- LICENSE.txt
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- bin/console
|
100
|
+
- bin/setup
|
101
|
+
- cash-addr.gemspec
|
102
|
+
- circle.yml
|
103
|
+
- doc/CashAddr.html
|
104
|
+
- doc/CashAddr/Converter.html
|
105
|
+
- doc/CashAddr/InvalidAddress.html
|
106
|
+
- doc/LICENSE_txt.html
|
107
|
+
- doc/README_md.html
|
108
|
+
- doc/cash-addr_gemspec.html
|
109
|
+
- doc/created.rid
|
110
|
+
- doc/css/fonts.css
|
111
|
+
- doc/css/rdoc.css
|
112
|
+
- doc/fonts/Lato-Light.ttf
|
113
|
+
- doc/fonts/Lato-LightItalic.ttf
|
114
|
+
- doc/fonts/Lato-Regular.ttf
|
115
|
+
- doc/fonts/Lato-RegularItalic.ttf
|
116
|
+
- doc/fonts/SourceCodePro-Bold.ttf
|
117
|
+
- doc/fonts/SourceCodePro-Regular.ttf
|
118
|
+
- doc/images/add.png
|
119
|
+
- doc/images/arrow_up.png
|
120
|
+
- doc/images/brick.png
|
121
|
+
- doc/images/brick_link.png
|
122
|
+
- doc/images/bug.png
|
123
|
+
- doc/images/bullet_black.png
|
124
|
+
- doc/images/bullet_toggle_minus.png
|
125
|
+
- doc/images/bullet_toggle_plus.png
|
126
|
+
- doc/images/date.png
|
127
|
+
- doc/images/delete.png
|
128
|
+
- doc/images/find.png
|
129
|
+
- doc/images/loadingAnimation.gif
|
130
|
+
- doc/images/macFFBgHack.png
|
131
|
+
- doc/images/package.png
|
132
|
+
- doc/images/page_green.png
|
133
|
+
- doc/images/page_white_text.png
|
134
|
+
- doc/images/page_white_width.png
|
135
|
+
- doc/images/plugin.png
|
136
|
+
- doc/images/ruby.png
|
137
|
+
- doc/images/tag_blue.png
|
138
|
+
- doc/images/tag_green.png
|
139
|
+
- doc/images/transparent.png
|
140
|
+
- doc/images/wrench.png
|
141
|
+
- doc/images/wrench_orange.png
|
142
|
+
- doc/images/zoom.png
|
143
|
+
- doc/index.html
|
144
|
+
- doc/js/darkfish.js
|
145
|
+
- doc/js/jquery.js
|
146
|
+
- doc/js/navigation.js
|
147
|
+
- doc/js/navigation.js.gz
|
148
|
+
- doc/js/search.js
|
149
|
+
- doc/js/search_index.js
|
150
|
+
- doc/js/search_index.js.gz
|
151
|
+
- doc/js/searcher.js
|
152
|
+
- doc/js/searcher.js.gz
|
153
|
+
- doc/table_of_contents.html
|
154
|
+
- lib/cash_addr.rb
|
155
|
+
- lib/cash_addr/address.rb
|
156
|
+
- lib/cash_addr/crypto.rb
|
157
|
+
- lib/cash_addr/version.rb
|
158
|
+
homepage: https://github.com/coinbase/cash-addr
|
159
|
+
licenses:
|
160
|
+
- Apache-2.0
|
161
|
+
metadata: {}
|
162
|
+
post_install_message:
|
163
|
+
rdoc_options: []
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
requirements: []
|
177
|
+
rubyforge_project:
|
178
|
+
rubygems_version: 2.7.4
|
179
|
+
signing_key:
|
180
|
+
specification_version: 4
|
181
|
+
summary: Library to convert between base58 and CashAddr BCH addresses
|
182
|
+
test_files: []
|