base32h 0.1.0

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.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +14 -0
  3. data/README.md +42 -0
  4. data/lib/base32h.rb +173 -0
  5. metadata +61 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: de7e1abc9f5fbb560cd132ff8c7d11c0c8c91e3b751d2031988de46cc3072b7b
4
+ data.tar.gz: 734e6651e89a697c7d8faeee81351a235a2d3473215e027cd7b7cae1897685d6
5
+ SHA512:
6
+ metadata.gz: 2022dfbdefa1e442441a68118e1cc82a497f75f703e23f98b0078a6c93f482225ce21fc66388e826f76d6aa47b7401ae69075b43ce59d40837664a0aab1ecd68
7
+ data.tar.gz: 93b45da982c68477c84ff31ec3926038c24f26d1b1fb7aa94551b50bcf17a79f9e48099e4f1a10f334b20df25ca78dcecf89b725fe28549d8447cf7d8b9edc95
data/COPYING ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2020 Ryan S. Northrup ("RyNo") <northrup@yellowapple.us>
2
+
3
+ Permission to use, copy, modify, and distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
8
+ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
9
+ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
10
+ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
11
+ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
12
+ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
13
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+ PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,42 @@
1
+ # `base32h.rb`
2
+
3
+ ## What is it?
4
+
5
+ It's the third reference implementation of an encoder and decoder for
6
+ Base32H, a new(-ish) duotrigesimal (that is: base-32) number
7
+ representation, written as a gem for Ruby.
8
+
9
+ ## How do I install it?
10
+
11
+ Run `gem install base32h`, or include it in your `Gemfile`, or
12
+ whatever you would normally do to install a gem.
13
+
14
+ ## How do I hack it?
15
+
16
+ ```bash
17
+ git clone --recursive https://github.com/base32h/base32h.rb.git
18
+ cd base32h.rb
19
+ rspec # to run the test suite
20
+ ```
21
+
22
+ ## How do I use it?
23
+
24
+ ```ruby
25
+ require 'base32h'
26
+
27
+ Base32H.encode 17854910
28
+ # => "H0WDY"
29
+
30
+ Base32H.encode_bin "\xE3\xA9H\x83\x8D\xF5\xD5\x96\xD9\xD9"
31
+ # => "WELLH0WDYPARDNER"
32
+
33
+ Base32H.decode '88pzd'
34
+ # => 8675309
35
+
36
+ Base32H.decode_bin('2060w2g6009').unpack('C*')
37
+ # => [0, 0, 0, 8, 6, 7, 5, 3, 0, 9]
38
+ ```
39
+
40
+ ## Am I allowed to use it?
41
+
42
+ Yep! Just follow the terms of the ISC license (see `COPYING` in this repo).
@@ -0,0 +1,173 @@
1
+ ##
2
+ # This module provides Base32H encoding and decoding functions.
3
+ module Base32H
4
+ VERSION = "0.1.0"
5
+
6
+ extend self
7
+
8
+ ##
9
+ # The complete list of Base32H digits, as an array of strings; the
10
+ # index of the array is the numeric value of the digit(s) in the
11
+ # string at that index. The first character in each string is the
12
+ # "canonical" digit (i.e. the one that Base32H-conformant encoders
13
+ # *must* emit for that value); all other characters (if present) are
14
+ # "aliases" (i.e. alternate forms of that digit that
15
+ # Base32H-conformant decoders *must* accept and correctly decode to
16
+ # that value).
17
+ #
18
+ # For example, +digits[27]+ returns +'VvUu'+, meaning that the
19
+ # "canonical" digit of value 27 is +V+, and that +v+, +U+, and +u+
20
+ # are all "aliases" of that canonical digit and decode to a value of
21
+ # 27.
22
+ def digits
23
+ ['0Oo',
24
+ '1Ii',
25
+ '2',
26
+ '3',
27
+ '4',
28
+ '5Ss',
29
+ '6',
30
+ '7',
31
+ '8',
32
+ '9',
33
+ 'Aa',
34
+ 'Bb',
35
+ 'Cc',
36
+ 'Dd',
37
+ 'Ee',
38
+ 'Ff',
39
+ 'Gg',
40
+ 'Hh',
41
+ 'Jj',
42
+ 'Kk',
43
+ 'Ll',
44
+ 'Mm',
45
+ 'Nn',
46
+ 'Pp',
47
+ 'Qq',
48
+ 'Rr',
49
+ 'Tt',
50
+ 'VvUu',
51
+ 'Ww',
52
+ 'Xx',
53
+ 'Yy',
54
+ 'Zz']
55
+ end
56
+
57
+ ##
58
+ # :category: Encoding Digit
59
+ #
60
+ # Encodes an integer between 0 and 31 (inclusive) to its Base32H
61
+ # representation.
62
+ def encode_digit(d)
63
+ d = d.to_i
64
+ return nil unless (0..31).include? d
65
+ digits[d][0]
66
+ end
67
+
68
+ ##
69
+ # :category: Encoding Numeric
70
+ #
71
+ # Encodes an integer to its Base32H representation.
72
+ def encode(int)
73
+ rem = int.to_i.abs
74
+ out = []
75
+ return '0' if rem == 0
76
+ while rem > 0 do
77
+ out.unshift(encode_digit(rem % 32))
78
+ rem /= 32
79
+ end
80
+ out.join ''
81
+ end
82
+
83
+ ##
84
+ # :category: Encoding Binary
85
+ #
86
+ # Encodes a (binary) string to its Base32H representation.
87
+ def encode_bin(bin)
88
+ data = bin.unpack('C*')
89
+ extra = data.length % 5
90
+ data = ([0] * (5 - extra)) + data if extra > 0
91
+ out = []
92
+ data.each_slice(5) do |s|
93
+ chunk = bytes_to_u40 s
94
+ out.push encode(chunk).rjust(8, '0')
95
+ end
96
+ out.join ''
97
+ end
98
+
99
+ ##
100
+ # :category: Decoding Digit
101
+ #
102
+ # Decodes a single Base32H digit to its integer representation.
103
+ def decode_digit(d)
104
+ d = d.to_s
105
+ digits.find_index {|i| i.include? d}
106
+ end
107
+
108
+ ##
109
+ # :category: Decoding Numeric
110
+ #
111
+ # Decodes a Base32H number to its integer representation.
112
+ def decode(str)
113
+ res = str.to_s.chars.reverse.reduce({acc: 0, exp: 0}) do |state, char|
114
+ digit = decode_digit(char)
115
+ if digit.nil?
116
+ state
117
+ else
118
+ {acc: state[:acc] + (digit * 32**state[:exp]),
119
+ exp: state[:exp] + 1}
120
+ end
121
+ end
122
+ res[:acc]
123
+ end
124
+
125
+ ##
126
+ # :category: Decoding Binary
127
+ #
128
+ # Decodes a Base32H binary into a string of packed unsigned bytes.
129
+ def decode_bin(str)
130
+ data = str.chars.reject {|c| decode_digit(c).nil?}
131
+ extra = data.length % 8
132
+ data = (['0'] * (8 - extra)) + data if extra > 0
133
+ out = []
134
+ data.each_slice(8) do |s|
135
+ chunk = u40_to_bytes decode(s.join '')
136
+ out += chunk
137
+ end
138
+ out.pack('C*')
139
+ end
140
+
141
+ private
142
+
143
+ def u40_to_bytes(int)
144
+ rem = int.to_i.abs
145
+ out = []
146
+ while rem > 0 do
147
+ out.unshift(rem % 256)
148
+ rem /= 256
149
+ end
150
+ pad = 5 - out.length
151
+ out = ([0] * pad) + out if pad > 0
152
+ out
153
+ end
154
+
155
+ def bytes_to_u40(bytes)
156
+ bytes.reverse.reduce({acc:0,exp:0}) do |s,b|
157
+ {acc: s[:acc] + (b * 2**(8*s[:exp])),
158
+ exp: s[:exp] + 1}
159
+ end[:acc]
160
+ end
161
+ end
162
+
163
+ class Integer
164
+ def to_base32h
165
+ Base32H.encode(self)
166
+ end
167
+ end
168
+
169
+ class String
170
+ def to_base32h
171
+ Base32H.encode_bin(self)
172
+ end
173
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: base32h
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan S. Northrup ("RyNo")
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-10-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: An encoder/decoder library for Base32H
28
+ email: northrup@yellowapple.us
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - COPYING
34
+ - README.md
35
+ - lib/base32h.rb
36
+ homepage: https://base32h.github.io
37
+ licenses:
38
+ - ISC
39
+ metadata:
40
+ homepage_uri: https://base32h.github.io
41
+ source_code_uri: https://github.com/base32h/base32h.rb
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.1.2
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Base32H
61
+ test_files: []