Module: Philiprehberger::BaseConvert

Defined in:
lib/philiprehberger/base_convert.rb,
lib/philiprehberger/base_convert/base32.rb,
lib/philiprehberger/base_convert/base58.rb,
lib/philiprehberger/base_convert/base62.rb,
lib/philiprehberger/base_convert/base85.rb,
lib/philiprehberger/base_convert/version.rb

Defined Under Namespace

Modules: Base32, Base58, Base62, Base85 Classes: Error

Constant Summary collapse

GENERIC_ALPHABET =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
HEX_ALPHABET =
'0123456789abcdefABCDEF'
BASE64_ALPHABET =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-_'
BASE85_ALPHABET =
"#{(33..117).map(&:chr).join}z".freeze
DETECTION_ORDER =
[
  [:hex,    HEX_ALPHABET],
  [:base32, Base32::DECODE_MAP.keys.join],
  [:base58, Base58::ALPHABET],
  [:base62, Base62::ALPHABET],
  [:base64, BASE64_ALPHABET],
  [:base85, BASE85_ALPHABET]
].map { |name, chars| [name, chars.each_char.to_a.to_set] }.freeze
VERSION =
'0.4.0'

Class Method Summary collapse

Class Method Details

.base32_decode(string) ⇒ String

Decode a Crockford Base32 string

Parameters:

  • string (String)

    the Base32-encoded string

Returns:

  • (String)

    the decoded string

Raises:

  • (Error)

    if the string contains invalid characters



93
94
95
# File 'lib/philiprehberger/base_convert.rb', line 93

def self.base32_decode(string)
  Base32.decode(string)
end

.base32_encode(string) ⇒ String

Encode a string to Crockford Base32

Parameters:

  • string (String)

    the input string

Returns:

  • (String)

    the Base32-encoded string



84
85
86
# File 'lib/philiprehberger/base_convert.rb', line 84

def self.base32_encode(string)
  Base32.encode(string)
end

.base36_decode(string) ⇒ Integer

Decode a Base36 string to an integer

Parameters:

  • string (String)

    the Base36-encoded string

Returns:

  • (Integer)

    the decoded integer

Raises:

  • (Error)

    if the string contains invalid characters



128
129
130
# File 'lib/philiprehberger/base_convert.rb', line 128

def self.base36_decode(string)
  decode(string, base: 36)
end

.base36_encode(integer) ⇒ String

Encode an integer to Base36

Parameters:

  • integer (Integer)

    the input integer (must be >= 0)

Returns:

  • (String)

    the Base36-encoded string

Raises:

  • (Error)

    if the input is negative



119
120
121
# File 'lib/philiprehberger/base_convert.rb', line 119

def self.base36_encode(integer)
  encode(integer, base: 36)
end

.base58_decode(string) ⇒ String

Decode a Base58 string

Parameters:

  • string (String)

    the Base58-encoded string

Returns:

  • (String)

    the decoded string

Raises:

  • (Error)

    if the string contains invalid characters



58
59
60
# File 'lib/philiprehberger/base_convert.rb', line 58

def self.base58_decode(string)
  Base58.decode(string)
end

.base58_encode(string) ⇒ String

Encode a string to Base58 (Bitcoin alphabet)

Parameters:

  • string (String)

    the input string

Returns:

  • (String)

    the Base58-encoded string



49
50
51
# File 'lib/philiprehberger/base_convert.rb', line 49

def self.base58_encode(string)
  Base58.encode(string)
end

.base62_decode(string) ⇒ Integer

Decode a Base62 string to an integer

Parameters:

  • string (String)

    the Base62-encoded string

Returns:

  • (Integer)

    the decoded integer

Raises:

  • (Error)

    if the string contains invalid characters



76
77
78
# File 'lib/philiprehberger/base_convert.rb', line 76

def self.base62_decode(string)
  Base62.decode(string)
end

.base62_encode(integer) ⇒ String

Encode an integer to Base62

Parameters:

  • integer (Integer)

    the input integer (must be >= 0)

Returns:

  • (String)

    the Base62-encoded string

Raises:

  • (Error)

    if the input is negative



67
68
69
# File 'lib/philiprehberger/base_convert.rb', line 67

def self.base62_encode(integer)
  Base62.encode(integer)
end

.base85_decode(string) ⇒ String

Decode an ASCII85 string

Parameters:

  • string (String)

    the ASCII85-encoded string

Returns:

  • (String)

    the decoded string

Raises:

  • (Error)

    if the string contains invalid characters



110
111
112
# File 'lib/philiprehberger/base_convert.rb', line 110

def self.base85_decode(string)
  Base85.decode(string)
end

.base85_encode(string) ⇒ String

Encode a string to ASCII85

Parameters:

  • string (String)

    the input string

Returns:

  • (String)

    the ASCII85-encoded string



101
102
103
# File 'lib/philiprehberger/base_convert.rb', line 101

def self.base85_encode(string)
  Base85.encode(string)
end

.decode(string, base:) ⇒ Integer

Decode a string from an arbitrary base (2-62) to an integer

Parameters:

  • string (String)

    the encoded string

  • base (Integer)

    the source base (2-62)

Returns:

  • (Integer)

    the decoded integer

Raises:

  • (Error)

    if the base is out of range or string contains invalid characters



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/philiprehberger/base_convert.rb', line 187

def self.decode(string, base:)
  raise Error, 'base must be between 2 and 62' unless base.between?(2, 62)
  raise Error, 'input must be a non-empty string' if string.nil? || string.empty?

  alphabet = GENERIC_ALPHABET[0, base]
  num = 0

  string.each_char do |char|
    value = alphabet.index(char)
    raise Error, "invalid character for base #{base}: #{char}" if value.nil?

    num = (num * base) + value
  end

  num
end

.detect(string) ⇒ Symbol?

Detect the encoding of a string based on its character set

Returns the narrowest base whose alphabet fully covers the input. Empty strings and strings that match no known base return nil.

Parameters:

  • string (String)

    the input string

Returns:

  • (Symbol, nil)

    one of :hex, :base32, :base58, :base62, :base64, :base85, or nil



37
38
39
40
41
42
43
# File 'lib/philiprehberger/base_convert.rb', line 37

def self.detect(string)
  return nil if string.nil? || string.empty?

  unique_chars = string.each_char.to_a.to_set
  match = DETECTION_ORDER.find { |(_name, alphabet)| unique_chars.subset?(alphabet) }
  match&.first
end

.encode(integer, base:) ⇒ String

Encode an integer in an arbitrary base (2-62)

Parameters:

  • integer (Integer)

    the input integer (must be >= 0)

  • base (Integer)

    the target base (2-62)

Returns:

  • (String)

    the encoded string

Raises:

  • (Error)

    if the base is out of range or input is negative



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/philiprehberger/base_convert.rb', line 163

def self.encode(integer, base:)
  raise Error, 'base must be between 2 and 62' unless base.between?(2, 62)
  raise Error, 'input must be a non-negative integer' unless integer.is_a?(Integer) && integer >= 0

  return GENERIC_ALPHABET[0] if integer.zero?

  alphabet = GENERIC_ALPHABET[0, base]
  result = []
  num = integer

  while num.positive?
    num, remainder = num.divmod(base)
    result << alphabet[remainder]
  end

  result.reverse.join
end

.hex_decode(string) ⇒ String

Decode a hexadecimal string

Parameters:

  • string (String)

    the hex-encoded string

Returns:

  • (String)

    the decoded string

Raises:

  • (Error)

    if the input is nil, empty, odd-length, or contains invalid characters



148
149
150
151
152
153
154
155
# File 'lib/philiprehberger/base_convert.rb', line 148

def self.hex_decode(string)
  raise Error, 'input cannot be nil' if string.nil?
  raise Error, 'input cannot be empty' if string.empty?
  raise Error, 'invalid hex string: odd length' if string.length.odd?
  raise Error, "invalid hex character in: #{string}" unless string.match?(/\A[0-9a-fA-F]+\z/)

  [string].pack('H*')
end

.hex_encode(string) ⇒ String

Encode a string to hexadecimal

Parameters:

  • string (String)

    the input string

Returns:

  • (String)

    the hex-encoded string

Raises:

  • (Error)

    if the input is nil



137
138
139
140
141
# File 'lib/philiprehberger/base_convert.rb', line 137

def self.hex_encode(string)
  raise Error, 'input cannot be nil' if string.nil?

  string.unpack1('H*')
end