Remove keymaster; update dep
This commit is contained in:
parent
020d3f554b
commit
ea6667c05f
@ -831,7 +831,9 @@ do_make_key2(Name, Bin, Transform,
|
|||||||
#wallet{name = WalletName, poas = POAs, keys = Keys} = Current,
|
#wallet{name = WalletName, poas = POAs, keys = Keys} = Current,
|
||||||
T = transform(Transform),
|
T = transform(Transform),
|
||||||
Seed = T(Bin),
|
Seed = T(Bin),
|
||||||
Key = #key{name = KeyName, id = ID} = gd_key_master:make_key(Name, Seed),
|
{ID, Pair} = hz_key_master:make_key(Seed),
|
||||||
|
KeyName = case Name =:= "" of true -> ID; false -> Name end,
|
||||||
|
Key = #key{name = KeyName, id = ID, pair = Pair},
|
||||||
POA = #poa{name = KeyName, id = ID},
|
POA = #poa{name = KeyName, id = ID},
|
||||||
NewKeys = [Key | Keys],
|
NewKeys = [Key | Keys],
|
||||||
NewPOAs = [POA | POAs],
|
NewPOAs = [POA | POAs],
|
||||||
@ -870,7 +872,7 @@ t_xor(B, A) ->
|
|||||||
|
|
||||||
|
|
||||||
do_recover_key(Mnemonic, State) ->
|
do_recover_key(Mnemonic, State) ->
|
||||||
case gd_key_master:decode(Mnemonic) of
|
case hz_key_master:decode(Mnemonic) of
|
||||||
{ok, Seed} ->
|
{ok, Seed} ->
|
||||||
do_recover_key2(Seed, State);
|
do_recover_key2(Seed, State);
|
||||||
Error ->
|
Error ->
|
||||||
@ -880,7 +882,7 @@ do_recover_key(Mnemonic, State) ->
|
|||||||
|
|
||||||
do_recover_key2(Seed, State = #s{wallet = Current, wallets = Wallets, pass = Pass}) ->
|
do_recover_key2(Seed, State = #s{wallet = Current, wallets = Wallets, pass = Pass}) ->
|
||||||
#wallet{name = WalletName, keys = Keys, poas = POAs} = Current,
|
#wallet{name = WalletName, keys = Keys, poas = POAs} = Current,
|
||||||
Recovered = #key{id = ID, name = AccName} = gd_key_master:make_key("", Seed),
|
Recovered = #key{id = ID, name = AccName} = hz_key_master:make_key("", Seed),
|
||||||
case lists:keymember(ID, #key.id, Keys) of
|
case lists:keymember(ID, #key.id, Keys) of
|
||||||
false ->
|
false ->
|
||||||
NewKeys = [Recovered | Keys],
|
NewKeys = [Recovered | Keys],
|
||||||
@ -899,7 +901,7 @@ do_recover_key2(Seed, State = #s{wallet = Current, wallets = Wallets, pass = Pas
|
|||||||
do_mnemonic(ID, #s{wallet = #wallet{keys = Keys}}) ->
|
do_mnemonic(ID, #s{wallet = #wallet{keys = Keys}}) ->
|
||||||
case lists:keyfind(ID, #key.id, Keys) of
|
case lists:keyfind(ID, #key.id, Keys) of
|
||||||
#key{pair = #{secret := <<K:32/binary, _/binary>>}} ->
|
#key{pair = #{secret := <<K:32/binary, _/binary>>}} ->
|
||||||
Mnemonic = gd_key_master:encode(K),
|
Mnemonic = hz_key_master:encode(K),
|
||||||
{ok, Mnemonic};
|
{ok, Mnemonic};
|
||||||
false ->
|
false ->
|
||||||
{error, bad_key}
|
{error, bad_key}
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
%%% @doc
|
|
||||||
%%% Key functions go here.
|
|
||||||
%%%
|
|
||||||
%%% The main reason this is a module of its own is that in the original architecture
|
|
||||||
%%% it was a process rather than just a library of functions. Now that it exists, though,
|
|
||||||
%%% there is little motivation to cram everything here into the controller process's
|
|
||||||
%%% code.
|
|
||||||
%%% @end
|
|
||||||
|
|
||||||
-module(gd_key_master).
|
|
||||||
-vsn("0.5.4").
|
|
||||||
|
|
||||||
|
|
||||||
-export([make_key/2, encode/1, decode/1]).
|
|
||||||
-export([lcg/1]).
|
|
||||||
-include("gd.hrl").
|
|
||||||
|
|
||||||
|
|
||||||
make_key("", <<>>) ->
|
|
||||||
Pair = #{public := Public} = ecu_eddsa:sign_keypair(),
|
|
||||||
ID = gmser_api_encoder:encode(account_pubkey, Public),
|
|
||||||
Name = binary_to_list(ID),
|
|
||||||
#key{name = Name, id = ID, pair = Pair};
|
|
||||||
make_key("", Seed) ->
|
|
||||||
Pair = #{public := Public} = ecu_eddsa:sign_seed_keypair(Seed),
|
|
||||||
ID = gmser_api_encoder:encode(account_pubkey, Public),
|
|
||||||
Name = binary_to_list(ID),
|
|
||||||
#key{name = Name, id = ID, pair = Pair};
|
|
||||||
make_key(Name, <<>>) ->
|
|
||||||
Pair = #{public := Public} = ecu_eddsa:sign_keypair(),
|
|
||||||
ID = gmser_api_encoder:encode(account_pubkey, Public),
|
|
||||||
#key{name = Name, id = ID, pair = Pair};
|
|
||||||
make_key(Name, Seed) ->
|
|
||||||
Pair = #{public := Public} = ecu_eddsa:sign_seed_keypair(Seed),
|
|
||||||
ID = gmser_api_encoder:encode(account_pubkey, Public),
|
|
||||||
#key{name = Name, id = ID, pair = Pair}.
|
|
||||||
|
|
||||||
|
|
||||||
-spec encode(Secret) -> Phrase
|
|
||||||
when Secret :: binary(),
|
|
||||||
Phrase :: string().
|
|
||||||
%% @doc
|
|
||||||
%% The encoding and decoding procesures are written to be able to handle any
|
|
||||||
%% width of bitstring or binary and a variable size dictionary. The magic numbers
|
|
||||||
%% 32, 4096 and 12 have been dropped in because currently these are known, but that
|
|
||||||
%% will change in the future if the key size or type changes.
|
|
||||||
|
|
||||||
encode(Bin) ->
|
|
||||||
<<Number:(32 * 8)>> = Bin,
|
|
||||||
DictSize = 4096,
|
|
||||||
Words = read_words(),
|
|
||||||
% Width = chunksize(DictSize - 1, 2),
|
|
||||||
Width = 12,
|
|
||||||
Chunks = chunksize(Number, DictSize),
|
|
||||||
Binary = <<Number:(Chunks * Width)>>,
|
|
||||||
encode(Width, Binary, Words).
|
|
||||||
|
|
||||||
encode(Width, Bits, Words) ->
|
|
||||||
CheckSum = checksum(Width, Bits),
|
|
||||||
encode(Width, <<CheckSum:Width, Bits/bitstring>>, Words, []).
|
|
||||||
|
|
||||||
encode(_, <<>>, _, Acc) ->
|
|
||||||
unicode:characters_to_list(lists:join(" ", lists:reverse(Acc)));
|
|
||||||
encode(Width, Bits, Words, Acc) ->
|
|
||||||
<<I:Width, Rest/bitstring>> = Bits,
|
|
||||||
Word = lists:nth(I + 1, Words),
|
|
||||||
encode(Width, Rest, Words, [Word | Acc]).
|
|
||||||
|
|
||||||
|
|
||||||
-spec decode(Phrase) -> {ok, Secret} | {error, Reason}
|
|
||||||
when Phrase :: string(),
|
|
||||||
Secret :: binary(),
|
|
||||||
Reason :: bad_phrase | bad_word.
|
|
||||||
%% @doc
|
|
||||||
%% Reverses the encoded secret string back into its binary representation.
|
|
||||||
|
|
||||||
decode(Encoded) ->
|
|
||||||
DictSize = 4096,
|
|
||||||
Words = read_words(),
|
|
||||||
Width = chunksize(DictSize - 1, 2),
|
|
||||||
decode(Width, Words, Encoded).
|
|
||||||
|
|
||||||
decode(Width, Words, Encoded) when is_list(Encoded) ->
|
|
||||||
decode(Width, Words, list_to_binary(Encoded));
|
|
||||||
decode(Width, Words, Encoded) ->
|
|
||||||
Split = string:lexemes(Encoded, " "),
|
|
||||||
decode(Width, Words, Split, <<>>).
|
|
||||||
|
|
||||||
decode(Width, Words, [Word | Rest], Acc) ->
|
|
||||||
case find(Word, Words) of
|
|
||||||
{ok, N} -> decode(Width, Words, Rest, <<Acc/bitstring, N:Width>>);
|
|
||||||
Error -> Error
|
|
||||||
end;
|
|
||||||
decode(Width, _, [], Acc) ->
|
|
||||||
sumcheck(Width, Acc).
|
|
||||||
|
|
||||||
|
|
||||||
chunksize(N, C) ->
|
|
||||||
chunksize(N, C, 0).
|
|
||||||
|
|
||||||
chunksize(0, _, A) -> A;
|
|
||||||
chunksize(N, C, A) -> chunksize(N div C, C, A + 1).
|
|
||||||
|
|
||||||
|
|
||||||
read_words() ->
|
|
||||||
Path = filename:join([zx:get_home(), "priv", "words4096.txt"]),
|
|
||||||
{ok, Bin} = file:read_file(Path),
|
|
||||||
string:lexemes(Bin, "\n").
|
|
||||||
|
|
||||||
|
|
||||||
find(Word, Words) ->
|
|
||||||
find(Word, Words, 0).
|
|
||||||
|
|
||||||
find(Word, [Word | _], N) -> {ok, N};
|
|
||||||
find(Word, [_ | Rest], N) -> find(Word, Rest, N + 1);
|
|
||||||
find(Word, [], _) -> {error, {bad_word, Word}}.
|
|
||||||
|
|
||||||
|
|
||||||
checksum(Width, Bits) ->
|
|
||||||
checksum(Width, Bits, 0).
|
|
||||||
|
|
||||||
checksum(_, <<>>, Sum) ->
|
|
||||||
Sum;
|
|
||||||
checksum(Width, Bits, Sum) ->
|
|
||||||
<<N:Width, Rest/bitstring>> = Bits,
|
|
||||||
checksum(Width, Rest, N bxor Sum).
|
|
||||||
|
|
||||||
|
|
||||||
sumcheck(Width, Bits) ->
|
|
||||||
<<CheckSum:Width, Binary/bitstring>> = Bits,
|
|
||||||
case checksum(Width, Binary) =:= CheckSum of
|
|
||||||
true ->
|
|
||||||
<<N:(bit_size(Binary))>> = Binary,
|
|
||||||
{ok, <<N:(32 * 8)>>};
|
|
||||||
false ->
|
|
||||||
{error, bad_phrase}
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-spec lcg(integer()) -> integer().
|
|
||||||
%% A simple PRNG that fits into 32 bits and is easy to implement anywhere (Kotlin).
|
|
||||||
%% Specifically, it is a "linear congruential generator" of the Lehmer variety.
|
|
||||||
%% The constants used are based on recommendations from Park, Miller and Stockmeyer:
|
|
||||||
%% https://www.firstpr.com.au/dsp/rand31/p105-crawford.pdf#page=4
|
|
||||||
%%
|
|
||||||
%% The input value should be between 1 and 2^31-1.
|
|
||||||
%%
|
|
||||||
%% The purpose of this PRNG is for password-based dictionary shuffling.
|
|
||||||
|
|
||||||
lcg(N) ->
|
|
||||||
M = 16#7FFFFFFF,
|
|
||||||
A = 48271,
|
|
||||||
Q = 44488, % M div A
|
|
||||||
R = 3399, % M rem A
|
|
||||||
Div = N div Q,
|
|
||||||
Rem = N rem Q,
|
|
||||||
S = Rem * A,
|
|
||||||
T = Div * R,
|
|
||||||
Result = S - T,
|
|
||||||
case Result < 0 of
|
|
||||||
false -> Result;
|
|
||||||
true -> Result + M
|
|
||||||
end.
|
|
@ -5,7 +5,7 @@
|
|||||||
{author,"Craig Everett"}.
|
{author,"Craig Everett"}.
|
||||||
{desc,"A desktop client for the Gajumaru network of blockchain networks"}.
|
{desc,"A desktop client for the Gajumaru network of blockchain networks"}.
|
||||||
{package_id,{"otpr","gajudesk",{0,5,4}}}.
|
{package_id,{"otpr","gajudesk",{0,5,4}}}.
|
||||||
{deps,[{"otpr","hakuzaru",{0,5,1}},
|
{deps,[{"otpr","hakuzaru",{0,6,0}},
|
||||||
{"otpr","gmserialization",{0,1,3}},
|
{"otpr","gmserialization",{0,1,3}},
|
||||||
{"otpr","sophia",{9,0,0}},
|
{"otpr","sophia",{9,0,0}},
|
||||||
{"otpr","gmbytecode",{3,4,1}},
|
{"otpr","gmbytecode",{3,4,1}},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user