Merge fortuna to master #136
16
rebar.config
16
rebar.config
@ -2,10 +2,13 @@
|
||||
|
||||
{erl_opts, [debug_info]}.
|
||||
|
||||
{deps, [ {getopt, "1.0.1"}
|
||||
{deps, [ {eblake2, "1.0.0"}
|
||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||
{ref, "b55c372"}}}
|
||||
, {getopt, "1.0.1"}
|
||||
]}.
|
||||
|
||||
{escript_incl_apps, [aebytecode, getopt]}.
|
||||
{escript_incl_apps, [aebytecode, eblake2, aeserialization, getopt]}.
|
||||
{escript_main_app, aebytecode}.
|
||||
{escript_name, aefateasm}.
|
||||
{escript_emu_args, "%%!"}.
|
||||
@ -19,8 +22,8 @@
|
||||
]}.
|
||||
|
||||
|
||||
{relx, [{release, {aessembler, "0.0.1"},
|
||||
[aebytecode, getopt]},
|
||||
{relx, [{release, {aebytecode, "2.0.1"},
|
||||
[aebytecode, eblake2, getopt]},
|
||||
|
||||
{dev_mode, true},
|
||||
{include_erts, false},
|
||||
@ -28,7 +31,10 @@
|
||||
{extended_start_script, true}]}.
|
||||
|
||||
{profiles, [{binary, [
|
||||
{deps, [ {getopt, "1.0.1"}
|
||||
{deps, [ {eblake2, "1.0.0"}
|
||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||
{ref, "b55c372"}}}
|
||||
, {getopt, "1.0.1"}
|
||||
]},
|
||||
|
||||
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
|
||||
|
12
rebar.lock
12
rebar.lock
@ -1,10 +1,16 @@
|
||||
{"1.1.0",
|
||||
[{<<"enacl">>,
|
||||
{git,"https://github.com/aeternity/enacl.git",
|
||||
{ref,"26180f42c0b3a450905d2efd8bc7fd5fd9cece75"}},
|
||||
[{<<"aeserialization">>,
|
||||
{git,"https://github.com/aeternity/aeserialization.git",
|
||||
{ref,"b55c3726f4a21063721c68d6fa7fda39121edf11"}},
|
||||
0},
|
||||
{<<"base58">>,
|
||||
{git,"https://github.com/aeternity/erl-base58.git",
|
||||
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
||||
1},
|
||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]}
|
||||
].
|
||||
|
@ -1,148 +0,0 @@
|
||||
%%%=============================================================================
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% BLAKE2b implementation in Erlang - for details see: https://blake2.net
|
||||
%%% @end
|
||||
%%%=============================================================================
|
||||
|
||||
-module(aeb_blake2).
|
||||
|
||||
-export([ blake2b/2
|
||||
, blake2b/3
|
||||
]).
|
||||
|
||||
-define(MAX_64BIT, 16#ffffffffffffffff).
|
||||
|
||||
-spec blake2b(HashLen :: integer(), Msg :: binary()) -> {ok, binary()}.
|
||||
blake2b(HashLen, Msg) ->
|
||||
blake2b(HashLen, Msg, <<>>).
|
||||
|
||||
-spec blake2b(HashLen :: integer(), Msg :: binary(), Key :: binary()) -> {ok, binary()}.
|
||||
blake2b(HashLen, Msg0, Key) ->
|
||||
%% If message should be keyed, prepend message with padded key.
|
||||
Msg = <<(pad(128, Key))/binary, Msg0/binary>>,
|
||||
|
||||
%% Set up the initial state
|
||||
Init = (16#01010000 + (byte_size(Key) bsl 8) + HashLen),
|
||||
<<H0:64, H1_7/binary>> = blake_iv(),
|
||||
H = <<(H0 bxor Init):64, H1_7/binary>>,
|
||||
|
||||
%% Perform the compression - message will be chopped into 128-byte chunks.
|
||||
State = blake2b_compress(H, Msg, 0),
|
||||
|
||||
%% Just return the requested part of the hash
|
||||
{ok, binary_part(to_little_endian(State), {0, HashLen})}.
|
||||
|
||||
blake2b_compress(H, <<Chunk:(128*8), Rest/binary>>, BCompr) when Rest /= <<>> ->
|
||||
H1 = blake2b_compress(H, <<Chunk:(128*8)>>, BCompr + 128, false),
|
||||
blake2b_compress(H1, Rest, BCompr + 128);
|
||||
blake2b_compress(H, SmallChunk, BCompr) ->
|
||||
Size = byte_size(SmallChunk),
|
||||
FillSize = (128 - Size) * 8,
|
||||
blake2b_compress(H, <<SmallChunk/binary, 0:FillSize>>, BCompr + Size, true).
|
||||
|
||||
blake2b_compress(H, Chunk0, BCompr, Last) ->
|
||||
Chunk = to_big_endian(Chunk0),
|
||||
<<V0_11:(12*64), V12:64, V13:64, V14:64, V15:64>> = <<H/binary, (blake_iv())/binary>>,
|
||||
V12_ = V12 bxor (BCompr band ?MAX_64BIT),
|
||||
V13_ = V13 bxor ((BCompr bsr 64) band ?MAX_64BIT),
|
||||
V14_ = case Last of
|
||||
false -> V14;
|
||||
true -> V14 bxor ?MAX_64BIT
|
||||
end,
|
||||
V = <<V0_11:(12*64), V12_:64, V13_:64, V14_:64, V15:64>>,
|
||||
|
||||
<<VLow:(8*64), VHigh:(8*64)>> =
|
||||
lists:foldl(fun(Round, Vx) -> blake2b_mix(Round, Chunk, Vx) end, V, lists:seq(0, 11)),
|
||||
|
||||
<<HInt:(8*64)>> = H,
|
||||
<<((HInt bxor VLow) bxor VHigh):(8*64)>>.
|
||||
|
||||
blake2b_mix(Rnd, Chunk, V) ->
|
||||
<<V0:64, V1:64, V2:64, V3:64, V4:64, V5:64, V6:64, V7:64, V8:64,
|
||||
V9:64, V10:64, V11:64, V12:64, V13:64, V14:64, V15:64>> = V,
|
||||
<<M0:64, M1:64, M2:64, M3:64, M4:64, M5:64, M6:64, M7:64, M8:64,
|
||||
M9:64, M10:64, M11:64, M12:64, M13:64, M14:64, M15:64>> = Chunk,
|
||||
Ms = {M0, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15},
|
||||
M = fun(Ix) -> element(Ix+1, Ms) end,
|
||||
|
||||
[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15] = sigma(Rnd rem 10),
|
||||
|
||||
{Vx0, Vx4, Vx8, Vx12} = blake2b_mix(V0, V4, V8, V12, M(S0), M(S1)),
|
||||
{Vx1, Vx5, Vx9, Vx13} = blake2b_mix(V1, V5, V9, V13, M(S2), M(S3)),
|
||||
{Vx2, Vx6, Vx10, Vx14} = blake2b_mix(V2, V6, V10, V14, M(S4), M(S5)),
|
||||
{Vx3, Vx7, Vx11, Vx15} = blake2b_mix(V3, V7, V11, V15, M(S6), M(S7)),
|
||||
|
||||
{Vy0, Vy5, Vy10, Vy15} = blake2b_mix(Vx0, Vx5, Vx10, Vx15, M(S8), M(S9)),
|
||||
{Vy1, Vy6, Vy11, Vy12} = blake2b_mix(Vx1, Vx6, Vx11, Vx12, M(S10), M(S11)),
|
||||
{Vy2, Vy7, Vy8, Vy13} = blake2b_mix(Vx2, Vx7, Vx8, Vx13, M(S12), M(S13)),
|
||||
{Vy3, Vy4, Vy9, Vy14} = blake2b_mix(Vx3, Vx4, Vx9, Vx14, M(S14), M(S15)),
|
||||
|
||||
<<Vy0:64, Vy1:64, Vy2:64, Vy3:64, Vy4:64, Vy5:64, Vy6:64, Vy7:64, Vy8:64,
|
||||
Vy9:64, Vy10:64, Vy11:64, Vy12:64, Vy13:64, Vy14:64, Vy15:64>>.
|
||||
|
||||
blake2b_mix(Va, Vb, Vc, Vd, X, Y) ->
|
||||
Va1 = (Va + Vb + X) band ?MAX_64BIT,
|
||||
Vd1 = rotr64(32, Vd bxor Va1),
|
||||
|
||||
Vc1 = (Vc + Vd1) band ?MAX_64BIT,
|
||||
Vb1 = rotr64(24, Vb bxor Vc1),
|
||||
|
||||
Va2 = (Va1 + Vb1 + Y) band ?MAX_64BIT,
|
||||
Vd2 = rotr64(16, Va2 bxor Vd1),
|
||||
|
||||
Vc2 = (Vc1 + Vd2) band ?MAX_64BIT,
|
||||
Vb2 = rotr64(63, Vb1 bxor Vc2),
|
||||
|
||||
{Va2, Vb2, Vc2, Vd2}.
|
||||
|
||||
blake_iv() ->
|
||||
IV0 = 16#6A09E667F3BCC908,
|
||||
IV1 = 16#BB67AE8584CAA73B,
|
||||
IV2 = 16#3C6EF372FE94F82B,
|
||||
IV3 = 16#A54FF53A5F1D36F1,
|
||||
IV4 = 16#510E527FADE682D1,
|
||||
IV5 = 16#9B05688C2B3E6C1F,
|
||||
IV6 = 16#1F83D9ABFB41BD6B,
|
||||
IV7 = 16#5BE0CD19137E2179,
|
||||
<<IV0:64, IV1:64, IV2:64, IV3:64, IV4:64, IV5:64, IV6:64, IV7:64>>.
|
||||
|
||||
sigma(N) ->
|
||||
{_, Row} = lists:keyfind(N, 1, sigma()), Row.
|
||||
|
||||
sigma() ->
|
||||
[{0, [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]},
|
||||
{1, [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]},
|
||||
{2, [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4]},
|
||||
{3, [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8]},
|
||||
{4, [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13]},
|
||||
{5, [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9]},
|
||||
{6, [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11]},
|
||||
{7, [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10]},
|
||||
{8, [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5]},
|
||||
{9, [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]}].
|
||||
|
||||
rotr64(N, I64) ->
|
||||
<<I64rot:64>> = rotr641(N, <<I64:64>>),
|
||||
I64rot.
|
||||
|
||||
rotr641(16, <<X:(64-16), Y:16>>) -> <<Y:16, X:(64-16)>>;
|
||||
rotr641(24, <<X:(64-24), Y:24>>) -> <<Y:24, X:(64-24)>>;
|
||||
rotr641(32, <<X:(64-32), Y:32>>) -> <<Y:32, X:(64-32)>>;
|
||||
rotr641(63, <<X:(64-63), Y:63>>) -> <<Y:63, X:(64-63)>>.
|
||||
|
||||
pad(N, Bin) ->
|
||||
case (N - (byte_size(Bin) rem N)) rem N of
|
||||
0 -> Bin;
|
||||
Pad -> <<Bin/binary, 0:(Pad *8)>>
|
||||
end.
|
||||
|
||||
to_big_endian(Bin) -> to_big_endian(Bin, <<>>).
|
||||
to_big_endian(<<>>, Acc) -> Acc;
|
||||
to_big_endian(<<UInt64:1/little-unsigned-integer-unit:64, Rest/binary>>, Acc) ->
|
||||
to_big_endian(Rest, <<Acc/binary, UInt64:1/big-unsigned-integer-unit:64>>).
|
||||
|
||||
to_little_endian(Bin) -> to_little_endian(Bin, <<>>).
|
||||
to_little_endian(<<>>, Acc) -> Acc;
|
||||
to_little_endian(<<UInt64:1/big-unsigned-integer-unit:64, Rest/binary>>, Acc) ->
|
||||
to_little_endian(Rest, <<Acc/binary, UInt64:1/little-unsigned-integer-unit:64>>).
|
@ -350,10 +350,10 @@ asm_to_bytecode(AssemblerCode, Options) ->
|
||||
Signatures = serialize_sigs(Env),
|
||||
SymbolTable = serialize_symbol_table(Env),
|
||||
Annotatations = serialize_annotations(Env),
|
||||
ByteCode = << (aeb_rlp:encode(list_to_binary(ByteList)))/binary,
|
||||
(aeb_rlp:encode(list_to_binary(Signatures)))/binary,
|
||||
(aeb_rlp:encode(SymbolTable))/binary,
|
||||
(aeb_rlp:encode(Annotatations))/binary
|
||||
ByteCode = << (aeser_rlp:encode(list_to_binary(ByteList)))/binary,
|
||||
(aeser_rlp:encode(list_to_binary(Signatures)))/binary,
|
||||
(aeser_rlp:encode(SymbolTable))/binary,
|
||||
(aeser_rlp:encode(Annotatations))/binary
|
||||
>>,
|
||||
|
||||
case proplists:lookup(pp_hex_string, Options) of
|
||||
@ -366,14 +366,14 @@ asm_to_bytecode(AssemblerCode, Options) ->
|
||||
{Env, ByteCode}.
|
||||
|
||||
strip(ByteCode) ->
|
||||
{Code, _Rest} = aeb_rlp:decode_one(ByteCode),
|
||||
{Code, _Rest} = aeser_rlp:decode_one(ByteCode),
|
||||
Code.
|
||||
|
||||
bytecode_to_fate_code(Bytes, _Options) ->
|
||||
{ByteCode, Rest1} = aeb_rlp:decode_one(Bytes),
|
||||
{Signatures, Rest2} = aeb_rlp:decode_one(Rest1),
|
||||
{SymbolTable, Rest3} = aeb_rlp:decode_one(Rest2),
|
||||
{Annotations, <<>>} = aeb_rlp:decode_one(Rest3),
|
||||
{ByteCode, Rest1} = aeser_rlp:decode_one(Bytes),
|
||||
{Signatures, Rest2} = aeser_rlp:decode_one(Rest1),
|
||||
{SymbolTable, Rest3} = aeser_rlp:decode_one(Rest2),
|
||||
{Annotations, <<>>} = aeser_rlp:decode_one(Rest3),
|
||||
|
||||
Env1 = deserialize(ByteCode, #{ function => none
|
||||
, bb => 0
|
||||
@ -844,7 +844,7 @@ insert_fun({Name, Type, RetType}, Code, #{functions := Functions} = Env) ->
|
||||
|
||||
mk_hash(Id) ->
|
||||
%% Use first 4 bytes of blake hash
|
||||
{ok, <<A:8, B:8, C:8, D:8,_/binary>> } = aeb_blake2:blake2b(?HASH_BYTES, list_to_binary(Id)),
|
||||
{ok, <<A:8, B:8, C:8, D:8,_/binary>> } = eblake2:blake2b(?HASH_BYTES, list_to_binary(Id)),
|
||||
<<A,B,C,D>>.
|
||||
|
||||
%% Handle annotations
|
||||
|
@ -104,9 +104,9 @@ serialize(String) when ?IS_FATE_STRING(String),
|
||||
?FATE_STRING_SIZE(String) > 0,
|
||||
?FATE_STRING_SIZE(String) >= ?SHORT_STRING_SIZE ->
|
||||
Bytes = ?FATE_STRING_VALUE(String),
|
||||
<<?LONG_STRING, (aeb_rlp:encode(Bytes))/binary>>;
|
||||
<<?LONG_STRING, (aeser_rlp:encode(Bytes))/binary>>;
|
||||
serialize(?FATE_ADDRESS(Address)) when is_binary(Address) ->
|
||||
<<?ADDRESS, (aeb_rlp:encode(Address))/binary>>;
|
||||
<<?ADDRESS, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_TUPLE(T)) when size(T) > 0 ->
|
||||
S = size(T),
|
||||
L = tuple_to_list(T),
|
||||
@ -148,7 +148,7 @@ serialize(?FATE_VARIANT(Size, Tag, Values)) when 0 =< Size
|
||||
%% -----------------------------------------------------
|
||||
|
||||
rlp_integer(S) when S >= 0 ->
|
||||
aeb_rlp:encode(binary:encode_unsigned(S)).
|
||||
aeser_rlp:encode(binary:encode_unsigned(S)).
|
||||
|
||||
serialize_integer(I) when ?IS_FATE_INTEGER(I) ->
|
||||
V = ?FATE_INTEGER_VALUE(I),
|
||||
@ -187,28 +187,28 @@ deserialize2(<<?POS_SIGN:1, I:6, ?SMALL_INT:1, Rest/binary>>) ->
|
||||
deserialize2(<<?NEG_SIGN:1, I:6, ?SMALL_INT:1, Rest/binary>>) ->
|
||||
{?MAKE_FATE_INTEGER(-I), Rest};
|
||||
deserialize2(<<?NEG_BIG_INT, Rest/binary>>) ->
|
||||
{Bint, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{Bint, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?MAKE_FATE_INTEGER(-binary:decode_unsigned(Bint) - ?SMALL_INT_SIZE),
|
||||
Rest2};
|
||||
deserialize2(<<?POS_BIG_INT, Rest/binary>>) ->
|
||||
{Bint, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{Bint, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?MAKE_FATE_INTEGER(binary:decode_unsigned(Bint) + ?SMALL_INT_SIZE),
|
||||
Rest2};
|
||||
deserialize2(<<?NEG_BITS, Rest/binary>>) ->
|
||||
{Bint, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{Bint, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?FATE_BITS(-binary:decode_unsigned(Bint)), Rest2};
|
||||
deserialize2(<<?POS_BITS, Rest/binary>>) ->
|
||||
{Bint, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{Bint, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?FATE_BITS(binary:decode_unsigned(Bint)), Rest2};
|
||||
deserialize2(<<?LONG_STRING, Rest/binary>>) ->
|
||||
{String, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{String, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?MAKE_FATE_STRING(String), Rest2};
|
||||
deserialize2(<<S:6, ?SHORT_STRING:2, Rest/binary>>) ->
|
||||
String = binary:part(Rest, 0, S),
|
||||
Rest2 = binary:part(Rest, byte_size(Rest), - (byte_size(Rest) - S)),
|
||||
{?MAKE_FATE_STRING(String), Rest2};
|
||||
deserialize2(<<?ADDRESS, Rest/binary>>) ->
|
||||
{A, Rest2} = aeb_rlp:decode_one(Rest),
|
||||
{A, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?FATE_ADDRESS(A), Rest2};
|
||||
deserialize2(<<?TRUE, Rest/binary>>) ->
|
||||
{?FATE_TRUE, Rest};
|
||||
@ -223,7 +223,7 @@ deserialize2(<<?EMPTY_MAP, Rest/binary>>) ->
|
||||
deserialize2(<<?EMPTY_STRING, Rest/binary>>) ->
|
||||
{?FATE_EMPTY_STRING, Rest};
|
||||
deserialize2(<<?LONG_TUPLE, Rest/binary>>) ->
|
||||
{BSize, Rest1} = aeb_rlp:decode_one(Rest),
|
||||
{BSize, Rest1} = aeser_rlp:decode_one(Rest),
|
||||
N = binary:decode_unsigned(BSize) + ?SHORT_TUPLE_SIZE,
|
||||
{List, Rest2} = deserialize_elements(N, Rest1),
|
||||
{?FATE_TUPLE(list_to_tuple(List)), Rest2};
|
||||
@ -231,7 +231,7 @@ deserialize2(<<S:4, ?SHORT_TUPLE:4, Rest/binary>>) ->
|
||||
{List, Rest1} = deserialize_elements(S, Rest),
|
||||
{?FATE_TUPLE(list_to_tuple(List)), Rest1};
|
||||
deserialize2(<<?LONG_LIST, Rest/binary>>) ->
|
||||
{BLength, Rest1} = aeb_rlp:decode_one(Rest),
|
||||
{BLength, Rest1} = aeser_rlp:decode_one(Rest),
|
||||
Length = binary:decode_unsigned(BLength) + ?SHORT_LIST_SIZE,
|
||||
{List, Rest2} = deserialize_elements(Length, Rest1),
|
||||
{?MAKE_FATE_LIST(List), Rest2};
|
||||
@ -239,7 +239,7 @@ deserialize2(<<S:4, ?SHORT_LIST:4, Rest/binary>>) ->
|
||||
{List, Rest1} = deserialize_elements(S, Rest),
|
||||
{?MAKE_FATE_LIST(List), Rest1};
|
||||
deserialize2(<<?MAP, Rest/binary>>) ->
|
||||
{BSize, Rest1} = aeb_rlp:decode_one(Rest),
|
||||
{BSize, Rest1} = aeser_rlp:decode_one(Rest),
|
||||
Size = binary:decode_unsigned(BSize),
|
||||
{List, Rest2} = deserialize_elements(2*Size, Rest1),
|
||||
Map = insert_kv(List, #{}),
|
||||
|
@ -1,91 +0,0 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2017, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Implementation of the Recursive Length Prefix.
|
||||
%%%
|
||||
%%% https://github.com/ethereum/wiki/wiki/RLP
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeb_rlp).
|
||||
-export([ decode/1
|
||||
, decode_one/1
|
||||
, encode/1
|
||||
]).
|
||||
|
||||
-export_type([ encodable/0
|
||||
, encoded/0
|
||||
]).
|
||||
|
||||
-type encodable() :: [encodable()] | binary().
|
||||
-type encoded() :: <<_:8, _:_*8>>.
|
||||
|
||||
-define(UNTAGGED_SIZE_LIMIT , 55).
|
||||
-define(UNTAGGED_LIMIT , 127).
|
||||
-define(BYTE_ARRAY_OFFSET , 128).
|
||||
-define(LIST_OFFSET , 192).
|
||||
|
||||
|
||||
-spec encode(encodable()) -> encoded().
|
||||
encode(X) ->
|
||||
encode(X, []).
|
||||
|
||||
encode(<<B>> = X,_Opts) when B =< ?UNTAGGED_LIMIT ->
|
||||
%% An untagged value
|
||||
X;
|
||||
encode(X,_Opts) when is_binary(X) ->
|
||||
%% Byte array
|
||||
add_size(?BYTE_ARRAY_OFFSET, X);
|
||||
encode(L, Opts) when is_list(L) ->
|
||||
%% Lists items are encoded and concatenated
|
||||
ByteArray = << << (encode(X, Opts))/binary >> || X <- L >>,
|
||||
add_size(?LIST_OFFSET, ByteArray).
|
||||
|
||||
add_size(Offset, X) when byte_size(X) =< ?UNTAGGED_SIZE_LIMIT ->
|
||||
%% The size fits in one tagged byte
|
||||
<<(Offset + byte_size(X)), X/binary>>;
|
||||
add_size(Offset, X) when is_binary(X) ->
|
||||
%% The size itself needs to be encoded as a byte array
|
||||
%% Add the tagged size of the size byte array
|
||||
SizeBin = binary:encode_unsigned(byte_size(X)),
|
||||
TaggedSize = ?UNTAGGED_SIZE_LIMIT + Offset + byte_size(SizeBin),
|
||||
true = (TaggedSize < 256 ), %% Assert
|
||||
<<TaggedSize, SizeBin/binary, X/binary>>.
|
||||
|
||||
-spec decode(encoded()) -> encodable().
|
||||
decode(Bin) when is_binary(Bin), byte_size(Bin) > 0 ->
|
||||
case decode_one(Bin) of
|
||||
{X, <<>>} -> X;
|
||||
{X, Left} -> error({trailing, X, Bin, Left})
|
||||
end.
|
||||
|
||||
decode_one(<<X, B/binary>>) when X =< ?UNTAGGED_LIMIT ->
|
||||
%% Untagged value
|
||||
{<<X>>, B};
|
||||
decode_one(<<L, _/binary>> = B) when L < ?LIST_OFFSET ->
|
||||
%% Byte array
|
||||
{Size, Rest} = decode_size(B, ?BYTE_ARRAY_OFFSET),
|
||||
<<X:Size/binary, Tail/binary>> = Rest,
|
||||
{X, Tail};
|
||||
decode_one(<<_/binary>> = B) ->
|
||||
%% List
|
||||
{Size, Rest} = decode_size(B, ?LIST_OFFSET),
|
||||
<<X:Size/binary, Tail/binary>> = Rest,
|
||||
{decode_list(X), Tail}.
|
||||
|
||||
decode_size(<<L, B/binary>>, Offset) when L =< Offset + ?UNTAGGED_SIZE_LIMIT->
|
||||
%% One byte tagged size.
|
||||
{L - Offset, B};
|
||||
decode_size(<<_, 0, _/binary>>,_Offset) ->
|
||||
error(leading_zeroes_in_size);
|
||||
decode_size(<<L, B/binary>>, Offset) ->
|
||||
%% Actual size is in a byte array.
|
||||
BinSize = L - Offset - ?UNTAGGED_SIZE_LIMIT,
|
||||
<<Size:BinSize/unit:8, Rest/binary>> = B,
|
||||
{Size, Rest}.
|
||||
|
||||
decode_list(<<>>) -> [];
|
||||
decode_list(B) ->
|
||||
{Element, Rest} = decode_one(B),
|
||||
[Element|decode_list(Rest)].
|
@ -1,10 +1,12 @@
|
||||
{application, aebytecode,
|
||||
[{description, "Bytecode definitions, serialization and deserialization for aeternity."},
|
||||
{vsn, "2.0.0"},
|
||||
{vsn, "2.0.1"},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib,
|
||||
eblake2,
|
||||
aeserialization,
|
||||
getopt
|
||||
]},
|
||||
{env,[]},
|
||||
|
@ -54,12 +54,12 @@ sources() ->
|
||||
|
||||
check_roundtrip(File) ->
|
||||
AssemblerCode = read_file(File),
|
||||
{Env, ByteCode} = assemble(AssemblerCode),
|
||||
{_Env, ByteCode} = assemble(AssemblerCode),
|
||||
FateCode = disassemble(ByteCode),
|
||||
DissasmCode = aeb_fate_asm:to_asm(FateCode),
|
||||
io:format("~s~n", [AssemblerCode]),
|
||||
io:format("~s~n", [DissasmCode]),
|
||||
{Env2, ByteCode2} = assemble(DissasmCode),
|
||||
{_Env2, ByteCode2} = assemble(DissasmCode),
|
||||
Code1 = aeb_fate_asm:strip(ByteCode),
|
||||
Code2 = aeb_fate_asm:strip(ByteCode2),
|
||||
?assertEqual(Code1, Code2).
|
||||
|
Loading…
x
Reference in New Issue
Block a user