Compare commits

..

No commits in common. "master" and "uw-gmser_dyn-rewrite" have entirely different histories.

2 changed files with 13 additions and 160 deletions

View File

@ -13,13 +13,7 @@
safe_decode/2, safe_decode/2,
byte_size_for_type/1]). byte_size_for_type/1]).
-export([encode_keypair/1, -export_type([encoded/0]).
safe_decode_keypair/1]).
-export([unsafe_encode/2]). %% Encode without size checks
-export_type([encoded/0,
known_type/0]).
-type known_type() :: key_block_hash -type known_type() :: key_block_hash
| micro_block_hash | micro_block_hash
@ -44,7 +38,6 @@
| native_token | native_token
| commitment | commitment
| peer_pubkey | peer_pubkey
| hash
| state | state
| poi | poi
| state_trees | state_trees
@ -58,66 +51,14 @@
-type payload() :: binary(). -type payload() :: binary().
-type encoded() :: binary(). -type encoded() :: binary().
-type keypair() :: #{public := <<_:(32*8)>>, secret := <<_:(64*8)>>}.
-type encoded_keypair() :: #{binary() => binary()}.
-export_type([ keypair/0
, encoded_keypair/0 ]).
-define(BASE58, 1). -define(BASE58, 1).
-define(BASE64, 2). -define(BASE64, 2).
-spec encode_keypair(keypair()) -> encoded_keypair().
encode_keypair(#{public := Pub, secret := Sec}) ->
case Sec of
<<Seed:32/binary, Pub1:32/binary>> when Pub1 =:= Pub ->
#{ <<"pub">> => encode(account_pubkey, Pub)
, <<"priv">> => encode(account_seckey, Seed) };
_ ->
erlang:error(invalid_keypair)
end.
-spec safe_decode_keypair(encoded_keypair()) -> {'ok', keypair()} | {'error', atom()}.
safe_decode_keypair(#{<<"pub">> := EncPub, <<"priv">> := EncPriv}) ->
case safe_decode(account_pubkey, EncPub) of
{ok, Pub} ->
case safe_decode(account_seckey, EncPriv) of
{ok, Seed} when byte_size(Seed) =:= 32 ->
case enacl:sign_seed_keypair(Seed) of
#{public := Pub, secret := _} = KP ->
{ok, KP};
_ ->
{error, illegal_encoding}
end;
{ok, <<Seed:32/binary, Pub:32/binary>>} ->
case enacl:sign_seed_keypair(Seed) of
#{public := Pub} = KP ->
{ok, KP};
_ ->
{error, illegal_encoding}
end;
{ok, _} ->
{error, illegal_encoding};
{error, _} = Error1 ->
Error1
end;
Error ->
Error
end.
-spec encode(known_type(), payload() | gmser_id:id()) -> encoded(). -spec encode(known_type(), payload() | gmser_id:id()) -> encoded().
encode(id_hash, Payload) -> encode(id_hash, Payload) ->
{IdType, Val} = gmser_id:specialize(Payload), {IdType, Val} = gmser_id:specialize(Payload),
encode(id2type(IdType), Val); encode(id2type(IdType), Val);
encode(Type, Payload) -> encode(Type, Payload) ->
case type_size_check(Type, Payload) of
ok ->
unsafe_encode(Type, Payload);
{error, Reason} ->
erlang:error(Reason)
end.
unsafe_encode(Type, Payload) ->
Pfx = type2pfx(Type), Pfx = type2pfx(Type),
Enc = case type2enc(Type) of Enc = case type2enc(Type) of
?BASE58 -> base58_check(Payload); ?BASE58 -> base58_check(Payload);
@ -125,7 +66,6 @@ unsafe_encode(Type, Payload) ->
end, end,
<<Pfx/binary, "_", Enc/binary>>. <<Pfx/binary, "_", Enc/binary>>.
-spec decode(binary()) -> {known_type(), payload()}. -spec decode(binary()) -> {known_type(), payload()}.
decode(Bin0) -> decode(Bin0) ->
case split(Bin0) of case split(Bin0) of
@ -141,13 +81,6 @@ decode(Bin0) ->
erlang:error(missing_prefix) erlang:error(missing_prefix)
end. end.
type_size_check(account_seckey, Bin) ->
case byte_size(Bin) of
Sz when Sz =:= 32; Sz =:= 64 ->
ok;
_ ->
{error, incorrect_size}
end;
type_size_check(Type, Bin) -> type_size_check(Type, Bin) ->
case byte_size_for_type(Type) of case byte_size_for_type(Type) of
not_applicable -> ok; not_applicable -> ok;

View File

@ -22,39 +22,10 @@
, {native_token , 32} , {native_token , 32}
, {commitment , 32} , {commitment , 32}
, {peer_pubkey , 32} , {peer_pubkey , 32}
, {hash , 32}
, {state , 32} , {state , 32}
, {poi , not_applicable}]). , {poi , not_applicable}]).
encode_decode_test_() -> encode_decode_test_() ->
encode_decode_test_(?TYPES).
encode_decode_known_types_test_() ->
KnownTypes = known_types(),
SizedTypes = [{T, ?TEST_MODULE:byte_size_for_type(T)} || T <- KnownTypes],
encode_decode_test_(SizedTypes).
prefixes_are_known_types_test() ->
MappedPfxs = mapped_prefixes(),
KnownTypes = known_types(),
lists:foreach(
fun({Pfx, Type}) ->
case lists:member(Type, KnownTypes) of
true -> ok;
false ->
error({not_a_known_type, Pfx, Type})
end
end, MappedPfxs),
lists:foreach(
fun(Type) ->
case lists:keyfind(Type, 2, MappedPfxs) of
{_, _} -> ok;
false ->
error({has_no_mapped_prefix, Type})
end
end, KnownTypes).
encode_decode_test_(Types) ->
[{"Byte sizes are correct", [{"Byte sizes are correct",
fun() -> fun() ->
lists:foreach( lists:foreach(
@ -62,7 +33,7 @@ encode_decode_test_(Types) ->
{_Type, _, ByteSize} = {Type, ByteSize, {_Type, _, ByteSize} = {Type, ByteSize,
?TEST_MODULE:byte_size_for_type(Type)} ?TEST_MODULE:byte_size_for_type(Type)}
end, end,
Types) ?TYPES)
end end
}, },
{"Serialize/deserialize known types", {"Serialize/deserialize known types",
@ -79,7 +50,7 @@ encode_decode_test_(Types) ->
{Type, Key} = ?TEST_MODULE:decode(EncodedKey), {Type, Key} = ?TEST_MODULE:decode(EncodedKey),
{ok, Key} = ?TEST_MODULE:safe_decode(Type, EncodedKey) {ok, Key} = ?TEST_MODULE:safe_decode(Type, EncodedKey)
end, end,
Types) ?TYPES)
end end
}, },
{"Key size check works", {"Key size check works",
@ -87,18 +58,17 @@ encode_decode_test_(Types) ->
lists:foreach( lists:foreach(
fun({_Type, not_applicable}) -> ok; fun({_Type, not_applicable}) -> ok;
({Type, ByteSize}) -> ({Type, ByteSize}) ->
CheckIllegalSize = CheckIlligalSize =
fun(S) -> fun(S) ->
Key = <<42:S/unit:8>>, Key = <<42:S/unit:8>>,
?assertError(incorrect_size, ?TEST_MODULE:encode(Type, Key)), EncodedKey = ?TEST_MODULE:encode(Type, Key),
EncodedKey = ?TEST_MODULE:unsafe_encode(Type, Key), %% no size check
{error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, EncodedKey) {error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, EncodedKey)
end, end,
CheckIllegalSize(0), CheckIlligalSize(0),
CheckIllegalSize(ByteSize - 1), CheckIlligalSize(ByteSize - 1),
CheckIllegalSize(ByteSize + 1) CheckIlligalSize(ByteSize + 1)
end, end,
Types) ?TYPES)
end end
}, },
{"Missing prefix", {"Missing prefix",
@ -121,7 +91,7 @@ encode_decode_test_(Types) ->
<<_WholePrefix:3/unit:8, RestOfKey2/binary>> = EncodedKey, <<_WholePrefix:3/unit:8, RestOfKey2/binary>> = EncodedKey,
{error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, RestOfKey2) {error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, RestOfKey2)
end, end,
Types) ?TYPES)
end end
}, },
{"Piece of encoded key", {"Piece of encoded key",
@ -140,7 +110,7 @@ encode_decode_test_(Types) ->
{error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, HalfKey), {error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, HalfKey),
{error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, RestOfKey) {error, invalid_encoding} = ?TEST_MODULE:safe_decode(Type, RestOfKey)
end, end,
Types) ?TYPES)
end end
}, },
{"Encode/decode binary with only zeros", {"Encode/decode binary with only zeros",
@ -161,58 +131,8 @@ encode_decode_test_(Types) ->
Encoded1 = base58:binary_to_base58(Bin), Encoded1 = base58:binary_to_base58(Bin),
Decoded1 = base58:base58_to_binary(Encoded1), Decoded1 = base58:base58_to_binary(Encoded1),
?assertEqual(Bin, Decoded1) ?assertEqual(Bin, Decoded1)
end, Types) end, ?TYPES)
end, end,
Bins) Bins)
end}, end}
{"Encode/decode keypairs",
fun() ->
KP1 = enacl:sign_keypair(),
Enc1 = ?TEST_MODULE:encode_keypair(KP1),
{ok, KP1} = ?TEST_MODULE:safe_decode_keypair(Enc1),
KP2 = enacl:sign_keypair(),
Enc2 = ?TEST_MODULE:encode_keypair(KP2),
{ok, KP2} = ?TEST_MODULE:safe_decode_keypair(Enc2),
BadEnc = Enc1#{~"priv" => maps:get(~"priv", Enc2)},
{error, illegal_encoding} = ?TEST_MODULE:safe_decode_keypair(BadEnc)
end
},
{"Encode AND decode both 32-byte and 64-byte account_seckey",
fun() ->
%% Originally, we could encode a 64-byte seckey, but decode would fail.
#{public := Pub, secret := Sec} = enacl:sign_keypair(),
<<Seed:32/binary, Pub:32/binary>> = Sec,
EncSeed = ?TEST_MODULE:encode(account_seckey, Seed),
EncSec = ?TEST_MODULE:encode(account_seckey, Sec),
{ok, Seed} = ?TEST_MODULE:safe_decode(account_seckey, EncSeed),
{ok, Sec} = ?TEST_MODULE:safe_decode(account_seckey, EncSec)
end
}
]. ].
known_types() ->
Forms = get_forms(),
[{type, _, union, Types}] =
[Def || {attribute, _, type, {known_type, Def, []}} <- Forms],
[Name || {atom,_, Name} <- Types].
mapped_prefixes() ->
Forms = get_forms(),
[Clauses] = [Cs || {function,_,pfx2type,1,Cs} <- Forms],
Abst = [{B, A} || {clause,_,[B],[],[A]} <- Clauses],
lists:map(
fun({B, A}) ->
{eval_expr(B), eval_expr(A)}
end, Abst).
get_forms() ->
get_forms(code:which(?TEST_MODULE)).
get_forms(Beam) ->
{ok, {_, [{abstract_code, {raw_abstract_v1, Forms}}]}} =
beam_lib:chunks(Beam, [abstract_code]),
Forms.
eval_expr(Expr) ->
{value, Val, []} = erl_eval:expr(Expr, []),
Val.