Last active
October 31, 2017 10:20
-
-
Save paveltyk/c73a34fff3b8b51ea8289a3a14930c5c to your computer and use it in GitHub Desktop.
This is a port of ScatterSwap integer hashing function written in Ruby to Elixir. https://github.com/namick/scatter_swap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule ScatterSwap do | |
@moduledoc """ | |
Usage: | |
Pass a number (as an integer) and random spin to the 'hash' function and it will return an obfuscated version of it. | |
ScatterSwap.hash(1, 0) #=> 4517239960 | |
ScatterSwap.hash(2, 0) #=> 7023641925 | |
ScatterSwap.hash(42, 0) #=> 2912536240 | |
Pass that obfuscated value in 'reverse_hash' function and it will return the original integer. | |
ScatterSwap.reverse_hash(4517239960, 0) #=> 1 | |
ScatterSwap.reverse_hash(7023641925, 0) #=> 2 | |
ScatterSwap.reverse_hash(2912536240, 0) #=> 42 | |
""" | |
use Bitwise | |
alias ClientsbayEvents.ScatterSwap.ListRotate | |
def hash(digit, spin) when is_integer(digit) do | |
digit | |
|> Integer.to_string | |
|> String.pad_leading(10, "0") | |
|> String.graphemes | |
|> Enum.map(&(String.to_integer&1)) | |
|> swap(spin) | |
|> scatter(spin) | |
|> Enum.join | |
|> String.to_integer | |
end | |
def reverse_hash(string, spin) when is_binary(string) do | |
case Integer.parse(string) do | |
{digit, _} -> reverse_hash(digit, spin) | |
:error -> :error | |
end | |
end | |
def reverse_hash(digit, spin) when is_integer(digit) do | |
digit | |
|> Integer.to_string | |
|> String.pad_leading(10, "0") | |
|> String.graphemes | |
|> Enum.map(&(String.to_integer&1)) | |
|> unscatter(spin) | |
|> unswap(spin) | |
|> Enum.join | |
|> String.to_integer | |
end | |
defp swapper_map(idx, spin) when is_integer(idx), do: swapper_map(Enum.to_list(0..9), idx, spin) | |
defp swapper_map([], _, _), do: [] | |
defp swapper_map(list, idx, spin) do | |
i = 10 - Enum.count(list) | |
randomizer = idx + Bitwise.bxor(i, spin) | |
{el, list} = ListRotate.rotate(list, randomizer) |> List.pop_at(-1) | |
[el] ++ swapper_map(list, idx, spin) | |
end | |
defp swap(list, spin) do | |
list | |
|> Enum.with_index | |
|> Enum.map(fn {digit, index} -> Enum.at(swapper_map(index, spin), digit) end) | |
end | |
defp scatter(list, spin) do | |
randomizer = Bitwise.bxor(spin, Enum.sum(list)) | |
do_scatter(list, randomizer) | |
end | |
defp do_scatter([], _), do: [] | |
defp do_scatter(list, randomizer) do | |
{el, list} = ListRotate.rotate(list, randomizer) |> List.pop_at(-1) | |
[el] ++ do_scatter(list, randomizer) | |
end | |
defp unscatter(list, spin) do | |
randomizer = Bitwise.bxor(spin, Enum.sum(list)) | |
do_unscatter(list, [], randomizer) | |
end | |
defp do_unscatter([], unscattered_list, _), do: unscattered_list | |
defp do_unscatter(scattered_list, unscattered_list, randomizer) do | |
{el, rest} = List.pop_at(scattered_list, -1) | |
unrotated_list = ListRotate.rotate(unscattered_list ++ [el], randomizer * -1) | |
do_unscatter(rest, unrotated_list, randomizer) | |
end | |
defp unswap(list, spin) do | |
list | |
|> Enum.with_index | |
|> Enum.map(fn {digit, index} -> 9 - Enum.find_index(Enum.reverse(swapper_map(index, spin)), fn(el) -> el == digit end) end) | |
end | |
end | |
defmodule ScatterSwap.ListRotate do | |
def rotate(l, n \\ 1) | |
def rotate([], _), do: [] | |
def rotate(l, 0), do: l | |
def rotate([h | t], 1), do: t ++ [h] | |
def rotate(l, n) when n > 0, do: rotate(rotate(l, 1), n-1) | |
def rotate(l, n), do: right_rotate(l, -n) | |
def right_rotate(l, n \\ 1) | |
def right_rotate(l, n) when n > 0, do: Enum.reverse(l) |> rotate(n) |> Enum.reverse | |
def right_rotate(l, n), do: rotate(l, -n) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment