class HashMan::Hasher
Constants
- AlphabetError
- DEFAULT_ALPHABET
- DEFAULT_SEPS
- GUARD_DIV
- InputError
- MIN_ALPHABET_LENGTH
VERSION = “1.0.2”
- MinLengthError
- SEP_DIV
- SaltError
Attributes
alphabet[R]
guards[R]
min_hash_length[R]
salt[R]
seps[R]
Public Class Methods
new(salt = "", min_hash_length = 0, alphabet = DEFAULT_ALPHABET)
click to toggle source
# File lib/hashman/hasher.rb, line 17 def initialize(salt = "", min_hash_length = 0, alphabet = DEFAULT_ALPHABET) @salt = salt @min_hash_length = min_hash_length @alphabet = alphabet setup_alphabet end
Public Instance Methods
decode(hash)
click to toggle source
# File lib/hashman/hasher.rb, line 45 def decode(hash) return [] if hash.nil? || hash.empty? internal_decode(hash, @alphabet) end
decode_hex(hash)
click to toggle source
# File lib/hashman/hasher.rb, line 51 def decode_hex(hash) ret = "" numbers = decode(hash) numbers.length.times do |i| ret += numbers[i].to_s(16)[1 .. -1] end ret.upcase end
encode(*numbers)
click to toggle source
# File lib/hashman/hasher.rb, line 25 def encode(*numbers) numbers.flatten! if numbers.length == 1 if numbers.empty? || numbers.reject { |n| Integer(n) && n >= 0 }.any? "" else internal_encode(numbers) end end
encode_hex(str)
click to toggle source
# File lib/hashman/hasher.rb, line 35 def encode_hex(str) return "" unless hex_string?(str) numbers = str.scan(/[\w\W]{1,12}/).map do |num| "1#{num}".to_i(16) end encode(numbers) end
Protected Instance Methods
consistent_shuffle(alphabet, salt)
click to toggle source
# File lib/hashman/hasher.rb, line 142 def consistent_shuffle(alphabet, salt) return alphabet if salt.nil? || salt.empty? v = 0 p = 0 (alphabet.length-1).downto(1) do |i| v = v % salt.length p += n = salt[v].ord j = (n + v + p) % i tmp_char = alphabet[j] alphabet = alphabet[0, j] + alphabet[i] + alphabet[j + 1..-1] alphabet = alphabet[0, i] + tmp_char + alphabet[i + 1..-1] v += 1 end alphabet end
hash(input, alphabet)
click to toggle source
# File lib/hashman/hasher.rb, line 164 def hash(input, alphabet) num = input.to_i len = alphabet.length res = "" begin res = "#{alphabet[num % len]}#{res}" num = num.div(alphabet.length) end while num > 0 res end
internal_decode(hash, alphabet)
click to toggle source
# File lib/hashman/hasher.rb, line 113 def internal_decode(hash, alphabet) ret = [] breakdown = hash.gsub(/[#{@guards}]/, " ") array = breakdown.split(" ") i = [3,2].include?(array.length) ? 1 : 0 if breakdown = array[i] lottery = breakdown[0] breakdown = breakdown[1 .. -1].gsub(/[#{@seps}]/, " ") array = breakdown.split(" ") array.length.times do |i| sub_hash = array[i] buffer = lottery + salt + alphabet alphabet = consistent_shuffle(alphabet, buffer[0, alphabet.length]) ret.push unhash(sub_hash, alphabet) end if encode(ret) != hash ret = [] end end ret end
internal_encode(numbers)
click to toggle source
# File lib/hashman/hasher.rb, line 64 def internal_encode(numbers) ret = "" alphabet = @alphabet length = numbers.length hash_int = 0 length.times do |i| hash_int += (numbers[i] % (i + 100)) end lottery = ret = alphabet[hash_int % alphabet.length] length.times do |i| num = numbers[i] buf = lottery + salt + alphabet alphabet = consistent_shuffle(alphabet, buf[0, alphabet.length]) last = hash(num, alphabet) ret += last if (i + 1) < length num %= (last.ord + i) ret += seps[num % seps.length] end end if ret.length < min_hash_length ret = guards[(hash_int + ret[0].ord) % guards.length] + ret if ret.length < min_hash_length ret += guards[(hash_int + ret[2].ord) % guards.length] end end half_length = alphabet.length.div(2) while(ret.length < min_hash_length) alphabet = consistent_shuffle(alphabet, alphabet) ret = alphabet[half_length .. -1] + ret + alphabet[0, half_length] excess = ret.length - min_hash_length ret = ret[excess / 2, min_hash_length] if excess > 0 end ret end
unhash(input, alphabet)
click to toggle source
# File lib/hashman/hasher.rb, line 177 def unhash(input, alphabet) num = 0 input.length.times do |i| pos = alphabet.index(input[i]) raise InputError, "unable to unhash" unless pos num += pos * alphabet.length ** (input.length - i - 1) end num end
Private Instance Methods
hex_string?(string)
click to toggle source
# File lib/hashman/hasher.rb, line 285 def hex_string?(string) string.to_s.match(/\A[0-9a-fA-F]+\Z/) end
pick_characters(array, index)
click to toggle source
# File lib/hashman/hasher.rb, line 289 def pick_characters(array, index) array[0, index] + " " + array[index + 1 .. -1] end
setup_alphabet()
click to toggle source
# File lib/hashman/hasher.rb, line 193 def setup_alphabet validate_attributes @alphabet = uniq_characters(alphabet) validate_alphabet setup_seps setup_guards end
setup_guards()
click to toggle source
# File lib/hashman/hasher.rb, line 239 def setup_guards gc = (alphabet.length / GUARD_DIV).ceil if alphabet.length < 3 @guards = seps[0, gc] @seps = seps[gc .. -1] else @guards = alphabet[0, gc] @alphabet = alphabet[gc .. -1] end end
setup_seps()
click to toggle source
# File lib/hashman/hasher.rb, line 204 def setup_seps @seps = DEFAULT_SEPS seps.length.times do |i| # Seps should only contain characters present in alphabet, # and alphabet should not contains seps if j = alphabet.index(seps[i]) @alphabet = pick_characters(alphabet, j) else @seps = pick_characters(seps, i) end end alphabet.delete!(' ') seps.delete!(' ') @seps = consistent_shuffle(seps, salt) if seps.length == 0 || (alphabet.length / seps.length.to_f) > SEP_DIV seps_length = (alphabet.length / SEP_DIV).ceil seps_length = 2 if seps_length == 1 if seps_length > seps.length diff = seps_length - seps.length; @seps += alphabet[0, diff] @alphabet = alphabet[diff .. -1] else @seps = seps[0, seps_length] end end @alphabet = consistent_shuffle(alphabet, salt) end
uniq_characters(string)
click to toggle source
# File lib/hashman/hasher.rb, line 293 def uniq_characters(string) string.split('').uniq.join('') end
validate_alphabet()
click to toggle source
# File lib/hashman/hasher.rb, line 278 def validate_alphabet unless alphabet.length >= MIN_ALPHABET_LENGTH raise AlphabetError, "Alphabet must contain at least " + "#{MIN_ALPHABET_LENGTH} unique characters." end end
validate_attributes()
click to toggle source
# File lib/hashman/hasher.rb, line 256 def validate_attributes unless salt.kind_of?(String) raise SaltError, "The salt must be a String" end unless min_hash_length.kind_of?(Fixnum) raise MinLengthError, "The min length must be a Fixnum" end unless min_hash_length >= 0 raise MinLengthError, "The min length must be 0 or more" end unless alphabet.kind_of?(String) raise AlphabetError, "The alphabet must be a String" end if alphabet.include?(' ') raise AlphabetError, "The alphabet can’t include spaces" end end