cash-addr 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +35 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +53 -0
  8. data/LICENSE.txt +13 -0
  9. data/README.md +73 -0
  10. data/Rakefile +8 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +6 -0
  13. data/cash-addr.gemspec +31 -0
  14. data/circle.yml +7 -0
  15. data/doc/CashAddr.html +110 -0
  16. data/doc/CashAddr/Converter.html +277 -0
  17. data/doc/CashAddr/InvalidAddress.html +103 -0
  18. data/doc/LICENSE_txt.html +99 -0
  19. data/doc/README_md.html +175 -0
  20. data/doc/cash-addr_gemspec.html +125 -0
  21. data/doc/created.rid +11 -0
  22. data/doc/css/fonts.css +167 -0
  23. data/doc/css/rdoc.css +590 -0
  24. data/doc/fonts/Lato-Light.ttf +0 -0
  25. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  26. data/doc/fonts/Lato-Regular.ttf +0 -0
  27. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  28. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  29. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  30. data/doc/images/add.png +0 -0
  31. data/doc/images/arrow_up.png +0 -0
  32. data/doc/images/brick.png +0 -0
  33. data/doc/images/brick_link.png +0 -0
  34. data/doc/images/bug.png +0 -0
  35. data/doc/images/bullet_black.png +0 -0
  36. data/doc/images/bullet_toggle_minus.png +0 -0
  37. data/doc/images/bullet_toggle_plus.png +0 -0
  38. data/doc/images/date.png +0 -0
  39. data/doc/images/delete.png +0 -0
  40. data/doc/images/find.png +0 -0
  41. data/doc/images/loadingAnimation.gif +0 -0
  42. data/doc/images/macFFBgHack.png +0 -0
  43. data/doc/images/package.png +0 -0
  44. data/doc/images/page_green.png +0 -0
  45. data/doc/images/page_white_text.png +0 -0
  46. data/doc/images/page_white_width.png +0 -0
  47. data/doc/images/plugin.png +0 -0
  48. data/doc/images/ruby.png +0 -0
  49. data/doc/images/tag_blue.png +0 -0
  50. data/doc/images/tag_green.png +0 -0
  51. data/doc/images/transparent.png +0 -0
  52. data/doc/images/wrench.png +0 -0
  53. data/doc/images/wrench_orange.png +0 -0
  54. data/doc/images/zoom.png +0 -0
  55. data/doc/index.html +175 -0
  56. data/doc/js/darkfish.js +161 -0
  57. data/doc/js/jquery.js +4 -0
  58. data/doc/js/navigation.js +142 -0
  59. data/doc/js/navigation.js.gz +0 -0
  60. data/doc/js/search.js +109 -0
  61. data/doc/js/search_index.js +1 -0
  62. data/doc/js/search_index.js.gz +0 -0
  63. data/doc/js/searcher.js +229 -0
  64. data/doc/js/searcher.js.gz +0 -0
  65. data/doc/table_of_contents.html +94 -0
  66. data/lib/cash_addr.rb +59 -0
  67. data/lib/cash_addr/address.rb +109 -0
  68. data/lib/cash_addr/crypto.rb +95 -0
  69. data/lib/cash_addr/version.rb +7 -0
  70. 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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CashAddr
4
+ ##
5
+ # Version of the cash-addr gem.
6
+ VERSION = '0.1.1'
7
+ 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: []