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,
|
||||
T = transform(Transform),
|
||||
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},
|
||||
NewKeys = [Key | Keys],
|
||||
NewPOAs = [POA | POAs],
|
||||
@ -870,7 +872,7 @@ t_xor(B, A) ->
|
||||
|
||||
|
||||
do_recover_key(Mnemonic, State) ->
|
||||
case gd_key_master:decode(Mnemonic) of
|
||||
case hz_key_master:decode(Mnemonic) of
|
||||
{ok, Seed} ->
|
||||
do_recover_key2(Seed, State);
|
||||
Error ->
|
||||
@ -880,7 +882,7 @@ do_recover_key(Mnemonic, State) ->
|
||||
|
||||
do_recover_key2(Seed, State = #s{wallet = Current, wallets = Wallets, pass = Pass}) ->
|
||||
#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
|
||||
false ->
|
||||
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}}) ->
|
||||
case lists:keyfind(ID, #key.id, Keys) of
|
||||
#key{pair = #{secret := <<K:32/binary, _/binary>>}} ->
|
||||
Mnemonic = gd_key_master:encode(K),
|
||||
Mnemonic = hz_key_master:encode(K),
|
||||
{ok, Mnemonic};
|
||||
false ->
|
||||
{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"}.
|
||||
{desc,"A desktop client for the Gajumaru network of blockchain networks"}.
|
||||
{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","sophia",{9,0,0}},
|
||||
{"otpr","gmbytecode",{3,4,1}},
|
||||
|
Loading…
x
Reference in New Issue
Block a user