Skip to content

Instantly share code, notes, and snippets.

@JamesTheAwesomeDude
Last active March 15, 2024 16:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JamesTheAwesomeDude/97ab8d893d8fbf42b739e40d3350489c to your computer and use it in GitHub Desktop.
Save JamesTheAwesomeDude/97ab8d893d8fbf42b739e40d3350489c to your computer and use it in GitHub Desktop.
[DRAFT] TeamSpeak 3 Hasher in Elixir
import Bitwise
require Logger
# "MEkDAgcAAgEgAh9n5rQmt3zJukGmwwvEVwfbZFS3NJ9oW7hgpJ0Db5ORAh8mOLmbP3+DfEQvEFbOcqymWoF6s9GHVcv8UegJBcWz" 3210790 1959110000000
defmodule TS3H do
def cmd_main(argv) do
[pk_str, ctr_best, ctr_cur] =
case argv do
[a, b, c] -> [a, b, c]
[a, b] -> [a, b, b]
end
{ctr_best, ""} = Integer.parse(ctr_best)
{ctr_cur, ""} = Integer.parse(ctr_cur)
improve_simple(pk_str, ctr_best, ctr_cur)
end
def improve_simple(pk_str, ctr_best, ctr_cur) do
# dumb, singlethreaded improvement.
# does not return if "met", only if "exceeded".
record = check(pk_str, ctr_best)
intervals(ctr_cur + 1)
|> Stream.map(fn range -> work_loop(pk_str, range, record) end)
|> Enum.find(fn {outcome, ctr, score} -> if outcome === :beat, do: {ctr, score} end)
end
defp work_loop(pk_str, range, target) do
intermed_state = phase1(pk_str)
Enum.reduce_while(
range,
{nil, -1, -1},
fn ctr, _ ->
case phase2(intermed_state, ctr) do
score when (score < target) ->
{:cont, {nil, ctr, score}}
score when (score == target) ->
{:halt, {:met, ctr, score}}
score when (score > target) ->
{:halt, {:beat, ctr, score}}
end
end
)
end
defp intervals(start \\ 0, size \\ 2**24) do
Stream.unfold(
start..(start+size-1),
fn range ->
{range, Range.shift(range, size)}
end
)
end
def check(pk_str, ctr) do
phase1(pk_str) |> phase2(ctr)
end
defp phase1(pk_str) do
:crypto.hash_init(:sha)
|> :crypto.hash_update(pk_str)
end
defp phase2(state, ctr) do
:crypto.hash_update(state, Integer.to_string(ctr))
|> :crypto.hash_final()
|> ts3_binary_lzcnt()
end
def ts3_binary_lzcnt(hash) do
# Octets are consumed starting from the lowest memory address.
# Bits are consumed starting from the least significant bit.
# Examples:
# <<255, 0, 0, 0>> -> 0
# << 1, 0, 0, 0>> -> 0
# << 0, 1, 0, 0>> -> 8
# << 0, 255, 0, 0>> -> 8
# << 0, 254, 0, 0>> -> 9
:binary.decode_unsigned(hash, :little)
|> ctzg(bit_size(hash))
end
defp ctzg(i, max \\ nil) when is_integer(i) do
# https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fctzg
if i === 0, do: max, else: ctz(i, 0)
end
defp ctz(i, count) do
if rem(i, 2) == 1 do
count
else
ctz(i >>> 1, count + 1)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment