Merge pull request 'Add keypair encoding, fix seckey size checks' (#57) from uw-account_seckey into master
All checks were successful
Gajumaru Serialization Tests / tests (push) Successful in -2m43s
All checks were successful
Gajumaru Serialization Tests / tests (push) Successful in -2m43s
Reviewed-on: #57
This commit is contained in:
commit
4698b54832
@ -13,8 +13,13 @@
|
|||||||
safe_decode/2,
|
safe_decode/2,
|
||||||
byte_size_for_type/1]).
|
byte_size_for_type/1]).
|
||||||
|
|
||||||
|
-export([encode_keypair/1,
|
||||||
|
safe_decode_keypair/1]).
|
||||||
|
|
||||||
|
-export([unsafe_encode/2]). %% Encode without size checks
|
||||||
|
|
||||||
-export_type([encoded/0,
|
-export_type([encoded/0,
|
||||||
known_type/0]).
|
known_type/0]).
|
||||||
|
|
||||||
-type known_type() :: key_block_hash
|
-type known_type() :: key_block_hash
|
||||||
| micro_block_hash
|
| micro_block_hash
|
||||||
@ -53,14 +58,66 @@
|
|||||||
-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);
|
||||||
@ -68,6 +125,7 @@ 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
|
||||||
@ -83,6 +141,13 @@ 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;
|
||||||
|
|||||||
@ -87,15 +87,16 @@ encode_decode_test_(Types) ->
|
|||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({_Type, not_applicable}) -> ok;
|
fun({_Type, not_applicable}) -> ok;
|
||||||
({Type, ByteSize}) ->
|
({Type, ByteSize}) ->
|
||||||
CheckIlligalSize =
|
CheckIllegalSize =
|
||||||
fun(S) ->
|
fun(S) ->
|
||||||
Key = <<42:S/unit:8>>,
|
Key = <<42:S/unit:8>>,
|
||||||
EncodedKey = ?TEST_MODULE:encode(Type, Key),
|
?assertError(incorrect_size, ?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,
|
||||||
CheckIlligalSize(0),
|
CheckIllegalSize(0),
|
||||||
CheckIlligalSize(ByteSize - 1),
|
CheckIllegalSize(ByteSize - 1),
|
||||||
CheckIlligalSize(ByteSize + 1)
|
CheckIllegalSize(ByteSize + 1)
|
||||||
end,
|
end,
|
||||||
Types)
|
Types)
|
||||||
end
|
end
|
||||||
@ -163,7 +164,30 @@ encode_decode_test_(Types) ->
|
|||||||
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() ->
|
known_types() ->
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user