Skip to content

Commit

Permalink
feat: merkleization of vectors (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
Godspower-Eze authored Jan 16, 2024
1 parent 445154b commit 54fa467
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
8 changes: 3 additions & 5 deletions lib/spec/runners/ssz_generic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ defmodule SszGenericTestRunner do
{:vector, _basic_type, _size} = schema,
real_serialized,
real_deserialized,
_expected_hash_tree_root
expected_hash_tree_root
) do
{:ok, deserialized} = SszEx.decode(real_serialized, schema)
assert deserialized == real_deserialized
Expand All @@ -92,11 +92,9 @@ defmodule SszGenericTestRunner do

assert serialized == real_serialized

# TODO
{:ok, actual_hash_tree_root} = SszEx.hash_tree_root(real_deserialized, schema)

# actual_hash_tree_root = SszEx.hash_tree_root!(real_deserialized, schema)

# assert actual_hash_tree_root == expected_hash_tree_root
assert actual_hash_tree_root == expected_hash_tree_root
end

defp assert_ssz("valid", schema, real_serialized, real_deserialized, expected_hash_tree_root) do
Expand Down
33 changes: 29 additions & 4 deletions lib/ssz_ex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,23 @@ defmodule LambdaEthereumConsensus.SszEx do
end
end

@spec hash_tree_root(list(), {:vector, any, non_neg_integer}) ::
{:ok, Types.root()} | {:error, String.t()}
def hash_tree_root(vector, {:vector, type, size}) do
if variable_size?(type) do
# TODO
# hash_tree_root_vector_complex_type(vector, {:vector, type, size}, limit)
{:error, "Not implemented"}
else
packed_chunks = pack(vector, {:list, type, size})
hash_tree_root_vector_basic_type(packed_chunks)
end
end

@spec hash_tree_root_list_basic_type(binary(), non_neg_integer, non_neg_integer) ::
{:ok, Types.root()} | {:error, String.t()}
def hash_tree_root_list_basic_type(chunks, limit, len) do
chunks_len = chunks |> byte_size() |> div(@bytes_per_chunk)
chunks_len = chunks |> get_chunks_len()

if chunks_len > limit do
{:error, "chunk size exceeds limit"}
Expand All @@ -100,14 +113,22 @@ defmodule LambdaEthereumConsensus.SszEx do
end
end

@spec hash_tree_root_vector_basic_type(binary()) ::
{:ok, Types.root()} | {:error, String.t()}
def hash_tree_root_vector_basic_type(chunks) do
leaf_count = chunks |> get_chunks_len() |> next_pow_of_two()
root = merkleize_chunks(chunks, leaf_count)
{:ok, root}
end

@spec mix_in_length(Types.root(), non_neg_integer) :: Types.root()
def mix_in_length(root, len) do
{:ok, serialized_len} = encode_int(len, @bits_per_chunk)
root |> hash_nodes(serialized_len)
end

def merkleize_chunks(chunks, leaf_count \\ nil) do
chunks_len = chunks |> byte_size() |> div(@bytes_per_chunk)
chunks_len = chunks |> get_chunks_len()

if chunks_len == 1 and leaf_count == nil do
chunks
Expand Down Expand Up @@ -151,8 +172,8 @@ defmodule LambdaEthereumConsensus.SszEx do
<<value::size(size)-little>> |> pack_bytes()
end

@spec pack(list(), {:list, any, non_neg_integer}) :: binary() | :error
def pack(list, {:list, schema, _size}) do
@spec pack(list(), {:list | :vector, any, non_neg_integer}) :: binary() | :error
def pack(list, {type, schema, _}) when type in [:vector, :list] do
if variable_size?(schema) do
# TODO
# pack_complex_type_list(list)
Expand Down Expand Up @@ -658,4 +679,8 @@ defmodule LambdaEthereumConsensus.SszEx do

<<left::binary, new_chunk::binary, right::binary>>
end

defp get_chunks_len(chunks) do
chunks |> byte_size() |> div(@bytes_per_chunk)
end
end

0 comments on commit 54fa467

Please sign in to comment.