base58block 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5d77a784c0b92e665ae1d0f03fb92307d78335d1
4
+ data.tar.gz: 628a12d811841276f0321339bae069db2642e07e
5
+ SHA512:
6
+ metadata.gz: cd87241e1e8d9561718520205a00c290d12c7fa80f3131b0f325d227b3476ae874f9d5443ac7acf93a4b629a3c30e8b02d25f6a0e7fa24f03632dbbe8cd29fd8
7
+ data.tar.gz: 1aaaaaef83a9f52d797c5356734a8c2f2632d74e41890423a236e3180a2ea220d7d507fa416053648f8a65180a1d89353bac26ca908de61f3c3e4c855ea14cb3
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in base58block.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 David Waite
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # Base58block
2
+
3
+ Implementation of the Base58 Block algorithm
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'base58block'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install base58block
20
+
21
+ ## Usage
22
+
23
+ The library itself currently just consists of an encode and decode method.
24
+
25
+ ### Encoding
26
+ The encoding is relatively simple. Using a 58 character dictionary
27
+ (matching the bitcoin dictionary), we divide the input into 8 byte (64 bit)
28
+ blocks, then convert these to 64 bit integers (in network octet order). This
29
+ block is converted to base58, with each base58 'digit' represented by a
30
+ different character in the dictionary. The value is always represented by a
31
+ full 11 base58 'digit' number. So for example:
32
+
33
+ ```ruby
34
+ Base58Block.encode "\0\0\0\0\0\0\0\0" # => "11111111"
35
+ ```
36
+
37
+ This is because the zero base58 digit is represented by the character "1" in
38
+ the dictionary.
39
+
40
+ The maximum value 64 bit number is represented in hex as 0xffffffffffffffff
41
+
42
+ ```ruby
43
+ Base58Block.encode(["FFFFFFFFFFFFFFFF"].pack("H*")) # => "jpXCZedGfVQ"
44
+ ```
45
+
46
+ You may need to represent the last bytes in a sequence total less than eight
47
+ bytes. This is done rather simply - pad the highest order bytes with zero values
48
+ before converting to an integer, convert to base58 per normal, then change the
49
+ highest order base58 'digit' to a flag value.
50
+
51
+ This flag value is `43 + {number of bytes in original block}`. This technique
52
+ was chosen because:
53
+ 1. The highest leading base58 'digit' for a 64 bit unsigned number will be 42,
54
+ so no Base58 value will ever result in the leading digit set to one of the
55
+ flag values
56
+ 2. The highest leading base58 'digit' for a 56 bit/7 byte unsigned number will
57
+ always be zero, so we will not lose information by assigning an additional
58
+ purpose to the leading digit.
59
+
60
+ To show an example:
61
+
62
+ ```ruby
63
+ # Convert the highest seven byte value, 0x00ffffffffffffff
64
+ result = Base58Block.encode(["00FFFFFFFFFFFFFF"].pack("H*")) # => "1Ahg1opVcGW"
65
+
66
+ # Change first 'digit' to indicate we had only seven bytes input
67
+ result[0] = DICTIONARY[43+7] # => "s"
68
+
69
+ Base58Block.encode(["FFFFFFFFFFFFFF".pack("H*")]) == result # => true
70
+ ```
71
+
72
+ Note that a partial block still results in 11 characters of output.
73
+
74
+ ###Decoding
75
+ Decoding works along the same lines as encoding, so it will likely be useful to
76
+ familiarize yourself with encoding before reading the following description.
77
+
78
+ Given an 11 character block, treat that block as a base58 number. The
79
+ individual 'digits' of this number are represented by the character values
80
+ within the dictionary. Reverse the dictionary mapping to come up with the
81
+ individual digit values of the base58 number. This will allow you to construct
82
+ an integer value, which should always be representable with an unsigned 64 bit
83
+ value. Then, convert this 64 bit value to network order bytes.
84
+
85
+ There is a special case when decoding a partial block. If the first 'digit' in
86
+ the base 58 value is 43 or higher, this value is a flag indicating a partial
87
+ block. Subtracting 43 from this value will give the number of bytes to be output
88
+ (1 - 7).
89
+
90
+ To convert this value to an integer, you should first set the leading 'digit' to
91
+ a zero value. You can then generate an eight byte output as normal. Strip off
92
+ the high order bytes (which will all be zero) to get a value of the desired size.
93
+
94
+ ### Normalization
95
+ For the purpose of cryptographic validity, it is useful to have a single source
96
+ value represented with a single base58 block encoded value. To this end, the
97
+ following additional rules are provided for normalization:
98
+
99
+ 1. Only the last block can be a partial block
100
+ 2. Partial blocks must indicate between 1 and 7 bytes
101
+ 3. No additional characters (including whitespace) may appear within the encoded
102
+ value.
103
+
104
+
105
+ ## Known issues
106
+
107
+ - The current decoding algorithm will fail if whitespace or invalid characters
108
+ are in the input value
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork it ( https://github.com/dwaite/base58block/fork )
113
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
114
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
115
+ 4. Push to the branch (`git push origin my-new-feature`)
116
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'base58block/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "base58block"
8
+ spec.version = Base58block::VERSION
9
+ spec.authors = ["David Waite"]
10
+ spec.email = ["david@alkaline-solutions.com"]
11
+ spec.summary = %q{Implementation of my own Base58-Block algorithm}
12
+ spec.description = %q{Encoding algorithm for human input of binary values}
13
+ spec.homepage = "https://github.com/dwaite/base58block"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,98 @@
1
+ require "base58block/version"
2
+
3
+ module Base58Block
4
+ DICTIONARY = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
5
+ REVERSE = [
6
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, nil, nil, nil, nil,
7
+ nil, nil, nil, 9, 10, 11, 12, 13, 14, 15, 16, nil, 17,
8
+ 18, 19, 20, 21, nil, 22, 23, 24, 25, 26, 27, 28, 29,
9
+ 30, 31, 32, nil, nil, nil, nil, nil, nil, 33, 34, 35, 36,
10
+ 37, 38, 39, 40, 41, 42, 43, nil, 44, 45, 46, 47, 48,
11
+ 49, 50, 51, 52, 53, 54, 55, 56, 57 ]
12
+ REVERSE_START = 49
13
+
14
+ private
15
+ def self.reverse_dictionary c
16
+ idx = c.bytes.first
17
+ if idx < REVERSE_START
18
+ nil
19
+ else
20
+ REVERSE[ idx - REVERSE_START]
21
+ end
22
+ end
23
+
24
+ public
25
+ def self.encode data
26
+ data = data.dup
27
+ result = ""
28
+
29
+ # operate on blocks of 8 bytes. The last block may less than 8 bytes
30
+ data.each_byte.each_slice(8) do |block|
31
+ encoded_block = ""
32
+ count = block.length
33
+
34
+ #convert input block into an integer using network order
35
+ total = block.inject {|sum, n| sum * 256 + n }
36
+
37
+ # repeatedly mod/divide
38
+ while total > 0 do
39
+ total, index = total.divmod 58
40
+ encoded_block << DICTIONARY[index]
41
+ end
42
+
43
+ # if output is less than 11 characters, pad with "1"
44
+ padding = 11 - encoded_block.bytesize
45
+ encoded_block << "1" * padding
46
+
47
+ # indicate less than eight bytes by changing the high order character
48
+ # (which is always '1' if you have less than eight bytes input) to
49
+ # a value which cannot occur
50
+ if count < 8
51
+ encoded_block[10] = DICTIONARY[43+count]
52
+ end
53
+
54
+ # We want the data to be in network order, so we reverse it now
55
+ encoded_block = encoded_block.reverse
56
+ result << encoded_block
57
+ end
58
+ result
59
+ end
60
+
61
+ def self.decode text
62
+ text = text.dup
63
+ result = "".force_encoding "binary"
64
+
65
+ # operate on blocks of 8 bytes. The last block may less than 8 bytes
66
+ text.each_char.each_slice(11) do |block|
67
+
68
+ # create an array of the individual base 58 'digits'
69
+ decoded_block = block.map{|c| reverse_dictionary c }
70
+ if decoded_block.include? nil
71
+ return nil
72
+ end
73
+
74
+ # decode the byte count, stripping off the flag if needed
75
+ byte_count = 8
76
+ if decoded_block[0] >= 43
77
+ byte_count = c[0] - 43
78
+ decoded_block = decoded_block[1..-1]
79
+ end
80
+
81
+ # convert to integer value
82
+ integer = decoded_block.inject{|sum, i| sum * 58 + i }
83
+
84
+ # convert integer to 8 byte array (in reverse order)
85
+ data = []
86
+ 8.times do
87
+ integer, mod = integer.divmod 256
88
+ data << mod
89
+ end
90
+ # strip off the leading zero bytes if we are a different byte count
91
+ data = data[0...byte_count].reverse
92
+
93
+ # pack bytes to a (binary) string and append to result
94
+ result << data.pack("C*")
95
+ end
96
+ result
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module Base58block
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: base58block
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - David Waite
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-08 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
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
+ description: Encoding algorithm for human input of binary values
42
+ email:
43
+ - david@alkaline-solutions.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - base58block.gemspec
54
+ - lib/base58block.rb
55
+ - lib/base58block/version.rb
56
+ homepage: https://github.com/dwaite/base58block
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.2.2
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Implementation of my own Base58-Block algorithm
80
+ test_files: []