Skip to content

Commit

Permalink
Nothing to see here..
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucassifoni committed Apr 9, 2024
1 parent fd73431 commit 6c9591f
Show file tree
Hide file tree
Showing 10 changed files with 320 additions and 211 deletions.
13 changes: 12 additions & 1 deletion ovo/lib/ovo/builtins.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,21 @@ defmodule Ovo.Builtins do
"lshift" => &lshift(&1, &2),
"rshift" => &rshift(&1, &2),
"xor" => &xor(&1, &2),
"overflow" => &overflow(&1, &2)
"overflow" => &overflow(&1, &2),
"hex" => &hex(&1, &2)
}
end

defp hex(nodes, env) do
case map_nodes(nodes, env) do
[%{kind: :integer, value: v}] ->
Ovo.Ast.string(Integer.to_string(v, 16))

_ ->
:error
end
end

defp overflow(nodes, env) do
import Bitwise

Expand Down
7 changes: 4 additions & 3 deletions ovo/lib/ovo/interpreter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ defmodule Ovo.Interpreter do
def run(code, input) when is_binary(code) do
tokens = Ovo.Tokenizer.tokenize(code)
{:ok, ast, _} = Ovo.Parser.parse(tokens)
rewritten = Ovo.Rewrites.rewrite(ast)
run(rewritten, input)
run(ast, input)
end

def run(%Ast{} = ast, input) do
Expand All @@ -53,7 +52,9 @@ defmodule Ovo.Interpreter do

register_pid(evaluator_pid, env)

{env, v} = evaluate(ast, env)
rewritten = Ovo.Rewrites.rewrite(ast)

{env, v} = evaluate(rewritten, env)

user_env = Env.get_user_env(env)
stop_env(evaluator_pid)
Expand Down
20 changes: 10 additions & 10 deletions ovo/lib/ovo/runner.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Ovo.Runner do
@type t() :: %{ast: Ovo.Ast.t(), code: binary(), hash: binary()}
@type t() :: %{ast: Ovo.Ast.t(), code: binary(), hash: binary(), name: binary()}

defstruct ast: nil, code: nil, hash: nil
defstruct ast: nil, code: "", hash: "", name: ""

@moduledoc """
An ovo Runner holds on an AST and is managed by an Ovo.Registry, holding on a stack of previous results.
Expand All @@ -15,20 +15,20 @@ defmodule Ovo.Runner do
Agent.start_link(fn -> initial_value end)
end

@spec register(binary()) :: {:ok, binary()} | {:error, any()}
def register(code, args \\ []) do
@spec register(binary(), binary()) :: {:ok, binary()} | {:error, any()}
def register(code, name, args \\ []) do
tokens = Ovo.Tokenizer.tokenize(code)
{:ok, ast, _} = Ovo.Parser.parse(tokens)
normalized_form = Ovo.Printer.print(ast)
hash = :crypto.hash(:sha256, normalized_form) |> Base.encode64() |> String.slice(0..8)
hash = :crypto.hash(:md5, normalized_form) |> Base.encode64() |> String.slice(0..3)
Logger.info("Registered program at hash #{hash}")

case Ovo.Registry.find_runner(hash) do
{:ok, _pid} ->
{:ok, hash}

{:error, _} ->
case Ovo.Runner.instantiate(ast, code, hash, args) do
case Ovo.Runner.instantiate(ast, code, name, hash, args) do
{:error, _reason} = e -> e
{:ok, _pid} -> {:ok, hash}
end
Expand Down Expand Up @@ -61,10 +61,10 @@ defmodule Ovo.Runner do
Ovo.Registry.pop_result(hash)
end

@spec instantiate(Ovo.Ast.t(), binary(), binary(), integer()) :: {:ok, pid()}
def instantiate(ast, code, hash, args) do
{:ok, pid} = start_link(%__MODULE__{ast: ast, code: code, hash: hash})
Ovo.Registry.register_runner(pid, hash, %{code: code, args: args})
@spec instantiate(Ovo.Ast.t(), binary(), binary(), binary(), integer()) :: {:ok, pid()}
def instantiate(ast, code, name, hash, args) do
{:ok, pid} = start_link(%__MODULE__{ast: ast, code: code, name: name, hash: hash})
Ovo.Registry.register_runner(pid, hash, %{code: code, name: name, args: args})
{:ok, pid}
end
end
47 changes: 28 additions & 19 deletions ovo/test/ovo_distribution_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ defmodule OvoDistributionTest do
result
"""

{:ok, hash1} = Ovo.Runner.register(code1)
{:ok, hash2} = Ovo.Runner.register(code2)
{:ok, hash1} = Ovo.Runner.register(code1, "foo")
{:ok, hash2} = Ovo.Runner.register(code2, "bar")

assert hash2 == "juRoIieFP"
assert hash2 == "1I9J"

assert %Ast{kind: :integer, value: 11, nodes: []} ==
Ovo.Registry.run_chain([hash2, hash1], [5])
Expand All @@ -34,7 +34,7 @@ defmodule OvoDistributionTest do
Ovo.Runner.shake(hash2)

assert %Ast{kind: :integer, value: 16, nodes: []} ==
Ovo.Runner.run("juRoIieFP", [8])
Ovo.Runner.run("1I9J", [8])
end

test "program linking 2" do
Expand All @@ -48,8 +48,8 @@ defmodule OvoDistributionTest do
add(arg(0), 1)
"""

{:ok, ovo_adder} = Ovo.Runner.register(adder)
{:ok, ovo_add_one} = Ovo.Runner.register(add_one)
{:ok, ovo_adder} = Ovo.Runner.register(adder, "foo")
{:ok, ovo_add_one} = Ovo.Runner.register(add_one, "bar")

add_and_add_one = fn a, b ->
Ovo.Registry.run_chain([ovo_adder, ovo_add_one], [a, b])
Expand All @@ -70,16 +70,16 @@ defmodule OvoDistributionTest do
result
"""

{:ok, hash} = Ovo.Runner.register(code)
{:ok, hash} = Ovo.Runner.register(code, "foo")

assert hash == "juRoIieFP"
assert hash == "1I9J"

code2 = """
z = add(arg(0), 5)
invoke(`juRoIieFP`, [z])
invoke(`1I9J`, [z])
"""

{:ok, dependent_hash} = Ovo.Runner.register(code2)
{:ok, dependent_hash} = Ovo.Runner.register(code2, "bar")

assert Ovo.Runner.run(dependent_hash, [3]) |> Ovo.Converter.ovo_to_elixir() == 16
end
Expand All @@ -91,23 +91,32 @@ defmodule OvoDistributionTest do
# Start some Ovo.Runners

{:ok, ovo_adder} =
Ovo.Runner.register("""
add(arg(0), arg(1))
""")
Ovo.Runner.register(
"""
add(arg(0), arg(1))
""",
"bar"
)

{:ok, ovo_times2} =
Ovo.Runner.register("""
multiply(arg(0), 2)
""")
Ovo.Runner.register(
"""
multiply(arg(0), 2)
""",
"baz"
)

%Ovo.Ast{value: 5} = Ovo.Runner.run(ovo_adder, [2, 3])
%Ovo.Ast{value: 10} = Ovo.Runner.run(ovo_times2, [5])
%Ovo.Ast{value: 10} = Ovo.Registry.run_chain([ovo_adder, ovo_times2], [2, 3])

{:ok, dependent_program} =
Ovo.Runner.register("""
invoke(`0ceaimhlh`, [2])
""")
Ovo.Runner.register(
"""
invoke(`9toz`, [2])
""",
"test"
)

%Ovo.Ast{value: 4} = Ovo.Runner.run(dependent_program, [])
%Ovo.Ast{value: 4} = Ovo.Runner.shake(dependent_program)
Expand Down
3 changes: 2 additions & 1 deletion ovo/test/ovo_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,10 @@ defmodule OvoTest do
hash = ~~(add(hash, ~~(hash << 3)))
hash = ~~(hash ^ (~~(hash >> 11)))
hash = ~~(add(hash, ~~(hash << 15)))
hex(hash)
"""

assert {%Ovo.Ast{kind: :integer, nodes: [], value: 0x519E91F5}, _} =
assert {%Ovo.Ast{kind: :string, nodes: [], value: "519E91F5"}, _} =
Ovo.run(input, "The quick brown fox jumps over the lazy dog")
end
end
122 changes: 97 additions & 25 deletions ovo_playground/lib/ovo_playground.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ defmodule OvoPlayground do
"""

def register_bottles_example do
# hashes to EWTiZxncF
# hashes to yfHDpFR9G
register = """
arg(0)
"""

# hashes to 5sxMB4BiC
# hashes to U2JfjlnOw
filler = """
foo = \\n ->
if equals(n, 0) then
0
else
invoke(`EWTiZxncF`, [n])
invoke(`yfHDpFR9G`, [n])
foo(subtract(n, 1))
end
end
foo(arg(0))
"""

# hashes to qjYwZaa3J
# hashes to 3wZLTOnsV
join = """
join = \\list, joiner ->
reduce(\\a, b ->
Expand All @@ -37,59 +37,131 @@ defmodule OvoPlayground do
join(arg(0), arg(1))
"""

# hashes to pgeqCPg/3
# hashes to bOtQKxR0l
last_bottle = """
terms = [arg(0), `bottle of beer on the wall`, arg(0), `bottle of beer.`, `Take one down and pass it around. No more bottles of beer on the wall.`]
invoke(`qjYwZaa3J`, [map(\\a -> to_string(a) end, terms), ` `])
invoke(`3wZLTOnsV`, [map(\\a -> to_string(a) end, terms), ` `])
"""

# hashes to QUl1z0wvi
# hashes to sYfB4ZArc
two_bottles = """
terms = [arg(0), `bottles of beer on the wall`, arg(0), `bottles of beer.`, `Take one down and pass it around`, subtract(arg(0), 1), `bottle of beer on the wall.`]
invoke(`qjYwZaa3J`, [map(\\a -> to_string(a) end, terms), ` `])
invoke(`3wZLTOnsV`, [map(\\a -> to_string(a) end, terms), ` `])
"""

# hashes to SLtzGVzyT
# hashes to 8CnXnHynu
normal_bottles = """
terms = [arg(0), `bottles of beer on the wall`, arg(0), `bottles of beer.`, `Take one down and pass it around`, subtract(arg(0), 1), `bottles of beer on the wall.`]
invoke(`qjYwZaa3J`, [map(\\a -> to_string(a) end, terms), ` `])
invoke(`3wZLTOnsV`, [map(\\a -> to_string(a) end, terms), ` `])
"""

full_song = """
n_bottles = subtract(100, rshake(`EWTiZxncF`))
n_bottles = subtract(100, rshake(`yfHDpFR9G`))
run = \\n, out ->
verse = if greater_or_equals(n, 3) then
invoke(`SLtzGVzyT`, [n])
invoke(`8CnXnHynu`, [n])
else
if greater_or_equals(n, 2) then
invoke(`QUl1z0wvi`, [n])
invoke(`sYfB4ZArc`, [n])
else
invoke(`pgeqCPg/3`, [n])
invoke(`bOtQKxR0l`, [n])
end
end
if equals(n, 0) then
out
else
nout = invoke(`qjYwZaa3J`, [[out, verse], ``])
run(subtract(100, rshake(`EWTiZxncF`)), nout)
nout = invoke(`3wZLTOnsV`, [[out, verse], ``])
run(subtract(100, rshake(`yfHDpFR9G`)), nout)
end
end
run(n_bottles, ` `)
"""

for {code, args} <- [
{register, ["0"]},
{filler, ["100"]},
{join, ["[\"a\"]", "\" \""]},
{last_bottle, ["1"]},
{two_bottles, ["1"]},
{normal_bottles, ["1"]},
{full_song, []}
for {code, name, args} <- [
{register, "register", ["0"]},
{filler, "filler", ["100"]},
{join, "joiner", ["[\"a\"]", "\" \""]},
{last_bottle, "last_bottle", ["1"]},
{two_bottles, "two_bottles", ["1"]},
{normal_bottles, "bottle", ["1"]},
{full_song, "full_song", []}
] do
Ovo.Runner.register(code, args)
Ovo.Runner.register(code, name, args)
end
end

def register_alice_examples() do
legitimate_hash = """
len = length(arg(0))
~~ = \\a -> overflow(a) end
cycle = \\h, i ->
if i == len then
h
else
out = ~~(add(h, intval(at(arg(0), i))))
out = ~~(add(out, ~~(out << 10)))
out = ~~(out ^ (~~((out >> 6))))
~~(cycle(out, add(i, 1)))
end
end
hash = ~~(cycle(0, 0))
hash = ~~(add(hash, ~~(hash << 3)))
hash = ~~(hash ^ (~~(hash >> 11)))
hash = ~~(add(hash, ~~(hash << 15)))
hex(hash)
"""

logger = """
arg(0)
"""

for {code, name, args} <- [
{legitimate_hash, "hash", ["\"the quick brown fox\""]},
{logger, "logger", ["100"]}
] do
Ovo.Runner.register(code, name, args)
end
end

def inject_code(injection) do
"""
len = length(arg(0))
~~ = \\a -> overflow(a) end
cycle = \\h, i ->
if i == len then
h
else
out = ~~(add(h, intval(at(arg(0), i))))
out = ~~(add(out, ~~(out << 10)))
out = ~~(out ^ (~~((out >> 6))))
~~(cycle(out, add(i, 1)))
end
end
foo = `#{injection}`
hash = ~~(cycle(0, 0))
hash = ~~(add(hash, ~~(hash << 3)))
hash = ~~(hash ^ (~~(hash >> 11)))
hash = ~~(add(hash, ~~(hash << 15)))
hex(hash)
"""
end

def find_collision() do
target = "yfHD"

for i <- 0..999_999_999_999_999 do
code = inject_code(i)
tokens = Ovo.Tokenizer.tokenize(code)
{:ok, ast, _} = Ovo.Parser.parse(tokens)
normalized_form = Ovo.Printer.print(ast)
hash = :crypto.hash(:md5, normalized_form) |> Base.encode64() |> String.slice(0..3)

if hash == target do
throw(i)
end
end
end
end
3 changes: 2 additions & 1 deletion ovo_playground/lib/ovo_playground/transforms.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ defmodule OvoPlayground.Transforms do
defp nodes(%Ovo.Ast{nodes: nodes}), do: nodes
defp concat(a, b), do: list(a) ++ list(b)

def maybe_rewrap({:ok, %Ovo.Ast{}=ast, []}, fun) do
def maybe_rewrap({:ok, %Ovo.Ast{} = ast, []}, fun) do
{:ok, fun.(ast), []}
end

def maybe_rewrap(%Ovo.Ast{} = ast, fun) do
fun.(ast)
end
Expand Down
Loading

0 comments on commit 6c9591f

Please sign in to comment.