Skip to content

Commit

Permalink
Merge 99c22d0 into 84396fc
Browse files Browse the repository at this point in the history
  • Loading branch information
vihu committed Aug 1, 2018
2 parents 84396fc + 99c22d0 commit 3b9b3a1
Show file tree
Hide file tree
Showing 7 changed files with 465 additions and 113 deletions.
386 changes: 298 additions & 88 deletions src/dkg_hybriddkg.erl

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/dkg_hybridvss.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
-type send_msg() :: {unicast, pos_integer(), {send, {session(), dkg_commitmentmatrix:serialized_matrix(), dkg_polynomial:polynomial()}}}.
-type echo_msg() :: {unicast, pos_integer(), {echo, {session(), dkg_commitmentmatrix:serialized_matrix(), binary()}}}.
-type ready_msg() :: {unicast, pos_integer(), {ready, {session(), dkg_commitmentmatrix:serialized_matrix(), binary()}}}.
-type result() :: {result, {session(), dkg_commitment:commitment(), [erlang_pbc:element()]}}.
-type result() :: {result, {session(), dkg_commitment:commitment(), [erlang_pbc:element()], map()}}.

-export_type([vss/0, session/0]).

Expand Down Expand Up @@ -132,7 +132,7 @@ handle_msg(State=#state{echoes=Echoes, id=Id, n=N, t=T, session=Session}, Sender
%% send the message (Pd, τ, ready, C, a(j)) to Pj
%% else if rC = n − t − f then
%% si ← a(0); output (Pd , τ, out, shared, C, si )
handle_msg(State=#state{readies=Readies, n=N, t=T, f=F, id=Id, commitment=Commitment}, Sender, {ready, {Session, SerializedCommitmentMatrix0, SA}}) ->
handle_msg(State=#state{readies=Readies, n=N, t=T, f=F, id=Id, commitment=Commitment}, Sender, {ready, {Session, SerializedCommitmentMatrix0, SA}}=ReadyMsg) ->
CommitmentMatrix0 = dkg_commitmentmatrix:deserialize(SerializedCommitmentMatrix0, State#state.u),
A = erlang_pbc:binary_to_element(State#state.u, SA),
case dkg_commitmentmatrix:verify_point(State#state.u2, CommitmentMatrix0, Sender, Id, A) of
Expand All @@ -150,16 +150,16 @@ handle_msg(State=#state{readies=Readies, n=N, t=T, f=F, id=Id, commitment=Commit
Msgs = lists:map(fun(Node) ->
{unicast, Node, {ready, {Session, SerializedCommitmentMatrix0, erlang_pbc:element_to_binary(lists:nth(Node+1, SubShares))}}}
end, dkg_util:allnodes(N)),
NewState = State#state{readies=maps:put(Sender, true, Readies), commitment=NewCommitment, received_commitment=true},
NewState = State#state{readies=maps:put(Sender, ReadyMsg, Readies), commitment=NewCommitment, received_commitment=true},
{NewState, {send, Msgs}};
false ->
case dkg_commitment:num_readies(NewCommitment) == (N-T-F) of
true->
[SubShare] = dkg_commitment:interpolate(NewCommitment, ready, []),
NewState = State#state{readies=maps:put(Sender, true, Readies), commitment=NewCommitment, received_commitment=true},
{NewState, {result, {Session, Commitment, SubShare}}};
NewState = State#state{readies=maps:put(Sender, ReadyMsg, Readies), commitment=NewCommitment, received_commitment=true},
{NewState, {result, {Session, Commitment, SubShare, NewState#state.readies}}};
false ->
NewState = State#state{readies=maps:put(Sender, true, Readies), commitment=NewCommitment, received_commitment=true},
NewState = State#state{readies=maps:put(Sender, ReadyMsg, Readies), commitment=NewCommitment, received_commitment=true},
{NewState, ok}
end
end;
Expand Down
8 changes: 4 additions & 4 deletions test/dkg_distributed_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ end_per_suite(Config) ->
Config.

init_per_testcase(TestCase, Config) ->
%% assuming each testcase will work with 5 nodes for now
NodeNames = [eric, kenny, kyle, ike, stan, randy, butters, token, jimmy, timmy],
%% assuming each testcase will work with 7 nodes for now
NodeNames = [eric, kenny, kyle, ike, stan, randy, butters],
Nodes = dkg_ct_utils:pmap(fun(Node) ->
dkg_ct_utils:start_node(Node, Config, TestCase)
end, NodeNames),

_ = [dkg_ct_utils:connect(Node) || Node <- NodeNames],

N = length(Nodes),
F = 3,
T = 1,
F = 0,
T = 2,
{ok, _} = ct_cover:add_nodes(Nodes),
[{nodes, Nodes}, {n, N}, {f, F}, {t, T} | Config].

Expand Down
133 changes: 125 additions & 8 deletions test/dkg_hybriddkg_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,32 @@

-export([all/0, init_per_testcase/2, end_per_testcase/2]).
-export([
init_test/1,
mnt224_test/1
symmetric_test/1,
asymmetric_test/1,
leader_change_symmetric_test/1,
leader_change_asymmetric_test/1
]).

all() ->
[
init_test,
mnt224_test
symmetric_test,
asymmetric_test,
leader_change_symmetric_test,
leader_change_asymmetric_test
].

init_per_testcase(_, Config) ->
N = list_to_integer(os:getenv("N", "10")),
F = 3,
T = 1,
F = 0,
T = 3,
Ph = 0,
Module = dkg_hybriddkg,
[{n, N}, {f, F}, {module, Module}, {t, T}, {ph, Ph} | Config].

end_per_testcase(_, _Config) ->
ok.

init_test(Config) ->
symmetric_test(Config) ->
N = proplists:get_value(n, Config),
F = proplists:get_value(f, Config),
T = proplists:get_value(t, Config),
Expand Down Expand Up @@ -86,7 +90,7 @@ init_test(Config) ->
?assertEqual(N, length(sets:to_list(ConvergedResults))),
ok.

mnt224_test(Config) ->
asymmetric_test(Config) ->
N = proplists:get_value(n, Config),
F = proplists:get_value(f, Config),
T = proplists:get_value(t, Config),
Expand Down Expand Up @@ -137,3 +141,116 @@ mnt224_test(Config) ->

?assertEqual(N, length(sets:to_list(ConvergedResults))),
ok.

leader_change_symmetric_test(Config) ->
N = proplists:get_value(n, Config),
F = proplists:get_value(f, Config),
T = proplists:get_value(t, Config),
Module = proplists:get_value(module, Config),
Group = erlang_pbc:group_new('SS512'),
G1 = erlang_pbc:element_from_hash(erlang_pbc:element_new('G1', Group), crypto:strong_rand_bytes(32)),
G2 = case erlang_pbc:pairing_is_symmetric(Group) of
true -> G1;
false -> erlang_pbc:element_from_hash(erlang_pbc:element_new('G2', Group), crypto:strong_rand_bytes(32))
end,

{StatesWithId, Replies} = lists:unzip(lists:map(fun(E) ->
{State, {send, Replies}} = Module:start(Module:init(E, N, F, T, G1, G2, {1, 0})),
{{E, State}, {E, {send, Replies}}}
end, lists:seq(2, N))),

{_FinalStates, ConvergedResults} = dkg_test_utils:do_send_outer(Module, Replies, StatesWithId, sets:new()),
ct:pal("Results ~p", [sets:to_list(ConvergedResults)]),

%% XXX: this is the same as the pubkeyshare test, I'm sure there is more to it
SecretKeyShares = lists:keysort(1, [ {Node, SecretKey} || {result, {Node, {SecretKey, _VerificationKey, _VerificationKeys}}} <- sets:to_list(ConvergedResults)]),
VerificationKeys = lists:keysort(1, [ {Node, VerificationKey} || {result, {Node, {_SecretKey, VerificationKey, _VerificationKeys}}} <- sets:to_list(ConvergedResults)]),
VerificationKeyss = lists:keysort(1, [ {Node, VerificationKeyz} || {result, {Node, {_SecretKey, _VerificationKey, VerificationKeyz}}} <- sets:to_list(ConvergedResults)]),
ct:pal("Secret key shares ~p", [[ erlang_pbc:element_to_string(S) || {_, S} <- SecretKeyShares]]),
ct:pal("Public key shares ~p", [[ erlang_pbc:element_to_string(S) || {_, S} <- VerificationKeys]]),
ct:pal("Public key shares ~p", [[ lists:map(fun erlang_pbc:element_to_string/1, S) || {_, S} <- VerificationKeyss]]),
PublicKeySharePoly = [Share || Share <- element(2, hd(VerificationKeyss))],
KnownSecret = dkg_polynomial:evaluate(PublicKeySharePoly, 0),
Indices = [ erlang_pbc:element_set(erlang_pbc:element_new('Zr', G1), I) || I <- lists:seq(1, N) ],
Alpha = erlang_pbc:element_set(erlang_pbc:element_new('Zr', G1), 0),
CalculatedSecret = dkg_lagrange:interpolate(PublicKeySharePoly, Indices, Alpha),
?assert(erlang_pbc:element_cmp(KnownSecret, CalculatedSecret)),

%% attempt to construct some TPKE keys...

PrivateKeys = lists:map(fun({result, {Node, {SK, VK, VKs}}}) ->
PK = tpke_pubkey:init(N, F, G1, G2, VK, VKs, 'SS512'),
tpke_privkey:init(PK, SK, Node-1)
end, sets:to_list(ConvergedResults)),
PubKey = tpke_privkey:public_key(hd(PrivateKeys)),
Msg = crypto:hash(sha256, crypto:strong_rand_bytes(12)),
MessageToSign = tpke_pubkey:hash_message(PubKey, Msg),
Signatures = [ tpke_privkey:sign(PrivKey, MessageToSign) || PrivKey <- PrivateKeys],
ct:pal("~p", [[tpke_pubkey:verify_signature_share(PubKey, Share, MessageToSign) || Share <- Signatures]]),
?assert(lists:all(fun(X) -> X end, [tpke_pubkey:verify_signature_share(PubKey, Share, MessageToSign) || Share <- Signatures])),
{ok, Sig} = tpke_pubkey:combine_signature_shares(PubKey, dealer:random_n(T+1, Signatures), MessageToSign),
?assert(tpke_pubkey:verify_signature(PubKey, Sig, MessageToSign)),

Message = crypto:hash(sha256, <<"my hovercraft is full of eels">>),
CipherText = tpke_pubkey:encrypt(PubKey, Message),
?assert(tpke_pubkey:verify_ciphertext(PubKey, CipherText)),
Shares = [ tpke_privkey:decrypt_share(SK, CipherText) || SK <- PrivateKeys ],
ct:pal("Decrypted shares ~p", [Shares]),
?assert(lists:all(fun(X) -> X end, [tpke_pubkey:verify_share(PubKey, Share, CipherText) || Share <- Shares])),
?assertEqual(Message, tpke_pubkey:combine_shares(PubKey, CipherText, dealer:random_n(T+1, Shares))),

?assertEqual(N-1, length(sets:to_list(ConvergedResults))),
ok.

leader_change_asymmetric_test(Config) ->
N = proplists:get_value(n, Config),
F = proplists:get_value(f, Config),
T = proplists:get_value(t, Config),
Module = proplists:get_value(module, Config),
Group = erlang_pbc:group_new('MNT224'),
G1 = erlang_pbc:element_from_hash(erlang_pbc:element_new('G1', Group), crypto:strong_rand_bytes(32)),
G2 = case erlang_pbc:pairing_is_symmetric(Group) of
true -> G1;
false -> erlang_pbc:element_from_hash(erlang_pbc:element_new('G2', Group), crypto:strong_rand_bytes(32))
end,

{StatesWithId, Replies} = lists:unzip(lists:map(fun(E) ->
{State, {send, Replies}} = Module:start(Module:init(E, N, F, T, G1, G2, {1, 0})),
{{E, State}, {E, {send, Replies}}}
end, lists:seq(2, N))),

{_FinalStates, ConvergedResults} = dkg_test_utils:do_send_outer(Module, Replies, StatesWithId, sets:new()),
%ct:pal("Results ~p", [sets:to_list(ConvergedResults)]),

%% XXX: this is the same as the pubkeyshare test, I'm sure there is more to it
SecretKeyShares = lists:keysort(1, [ {Node, SecretKey} || {result, {Node, {SecretKey, _VerificationKey, _VerificationKeys}}} <- sets:to_list(ConvergedResults)]),
VerificationKeys = lists:keysort(1, [ {Node, VerificationKey} || {result, {Node, {_SecretKey, VerificationKey, _VerificationKeys}}} <- sets:to_list(ConvergedResults)]),
VerificationKeyss = lists:keysort(1, [ {Node, VerificationKeyz} || {result, {Node, {_SecretKey, _VerificationKey, VerificationKeyz}}} <- sets:to_list(ConvergedResults)]),
ct:pal("Secret key shares ~p", [[ erlang_pbc:element_to_string(S) || {_, S} <- SecretKeyShares]]),
ct:pal("Public key shares ~p", [[ erlang_pbc:element_to_string(S) || {_, S} <- VerificationKeys]]),
ct:pal("Public key shares ~p", [[ lists:map(fun erlang_pbc:element_to_string/1, S) || {_, S} <- VerificationKeyss]]),
PublicKeySharePoly = [Share || Share <- element(2, hd(VerificationKeyss))],
KnownSecret = dkg_polynomial:evaluate(PublicKeySharePoly, 0),
Indices = [ erlang_pbc:element_set(erlang_pbc:element_new('Zr', G1), I) || I <- lists:seq(1, N) ],
Alpha = erlang_pbc:element_set(erlang_pbc:element_new('Zr', G1), 0),
CalculatedSecret = dkg_lagrange:interpolate(PublicKeySharePoly, Indices, Alpha),
?assert(erlang_pbc:element_cmp(KnownSecret, CalculatedSecret)),

%% attempt to construct some TPKE keys...

PrivateKeys = lists:map(fun({result, {Node, {SK, VK, VKs}}}) ->
PK = tpke_pubkey:init(N, F, G1, G2, VK, VKs, 'MNT224'),
tpke_privkey:init(PK, SK, Node-1)
end, sets:to_list(ConvergedResults)),
PubKey = tpke_privkey:public_key(hd(PrivateKeys)),
Msg = crypto:hash(sha256, crypto:strong_rand_bytes(12)),
MessageToSign = tpke_pubkey:hash_message(PubKey, Msg),
Signatures = [ tpke_privkey:sign(PrivKey, MessageToSign) || PrivKey <- PrivateKeys],
ct:pal("~p", [[tpke_pubkey:verify_signature_share(PubKey, Share, MessageToSign) || Share <- Signatures]]),
?assert(lists:all(fun(X) -> X end, [tpke_pubkey:verify_signature_share(PubKey, Share, MessageToSign) || Share <- Signatures])),
{ok, Sig} = tpke_pubkey:combine_signature_shares(PubKey, dealer:random_n(T+1, Signatures), MessageToSign),
?assert(tpke_pubkey:verify_signature(PubKey, Sig, MessageToSign)),

?assertEqual(N-1, length(sets:to_list(ConvergedResults))),
ok.

8 changes: 4 additions & 4 deletions test/dkg_hybridvss_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ init_test(Config) ->
{_FinalStates, ConvergedResults} = dkg_test_utils:do_send_outer(Module, [{1, {send, MsgsToSend}}], StatesWithId, sets:new()),

%% check that the shares from nodes can be interpolated to calculate the original secret back
NodesAndShares = lists:foldl(fun({result, {Node, {_Session, _Commitment, Share}}}, Acc) ->
NodesAndShares = lists:foldl(fun({result, {Node, {_Session, _Commitment, Share, _Rd}}}, Acc) ->
maps:put(Node, Share, Acc)
end, #{}, sets:to_list(ConvergedResults)),

AllCommitments = [Commitment || {result, {_Node, {_Session, Commitment, _Share}}} <- sets:to_list(ConvergedResults)],
AllCommitments = [Commitment || {result, {_Node, {_Session, Commitment, _Share, _Rd}}} <- sets:to_list(ConvergedResults)],
OutputCommitment = hd(AllCommitments),

%[VerificationKey | PublicKeyShares] = dkg_commitment:interpolate(OutputCommitment, ready, lists:seq(1, N)),
Expand Down Expand Up @@ -121,11 +121,11 @@ mnt224_test(Config) ->
{_FinalStates, ConvergedResults} = dkg_test_utils:do_send_outer(Module, [{1, {send, MsgsToSend}}], StatesWithId, sets:new()),

%% check that the shares from nodes can be interpolated to calculate the original secret back
NodesAndShares = lists:foldl(fun({result, {Node, {_Session, _Commitment, Share}}}, Acc) ->
NodesAndShares = lists:foldl(fun({result, {Node, {_Session, _Commitment, Share, _Rd}}}, Acc) ->
maps:put(Node, Share, Acc)
end, #{}, sets:to_list(ConvergedResults)),

AllCommitments = [Commitment || {result, {_Node, {_Session, Commitment, _Share}}} <- sets:to_list(ConvergedResults)],
AllCommitments = [Commitment || {result, {_Node, {_Session, Commitment, _Share, _Rd}}} <- sets:to_list(ConvergedResults)],
OutputCommitment = hd(AllCommitments),

%[VerificationKey | PublicKeyShares] = dkg_commitment:interpolate(OutputCommitment, ready, lists:seq(1, N)),
Expand Down
30 changes: 28 additions & 2 deletions test/dkg_test_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@

-export([do_send_outer/4, random_n/2]).

do_send_outer(_Mod, [], States, Acc) ->
{States, Acc};
do_send_outer(Mod, [], States, Acc) ->
case get_timers() of
[] ->
{States, Acc};
Timers ->
ct:pal("Timers ~p", [Timers]),
{R, NewStates} = do_send(Mod, {0, {send, [ {unicast, J, timeout} || J <- Timers]}}, [], States),
erlang:put(timers, []),
do_send_outer(Mod, R, NewStates, Acc)
end;
do_send_outer(Mod, [{result, {Id, Result}} | T], Pids, Acc) ->
do_send_outer(Mod, T, Pids, sets:add_element({result, {Id, Result}}, Acc));
do_send_outer(Mod, [H|T], States, Acc) ->
{R, NewStates} = do_send(Mod, H, [], States),
do_send_outer(Mod, T++R, NewStates, Acc).

do_send(_Mod, {Id, start_timer}, Acc, States) ->
set_timer(Id),
{Acc, States};
do_send(_Mod, {Id, {result, Result}}, Acc, States) ->
cancel_timer(Id),
{[{result, {Id, Result}} | Acc], States};
do_send(_Mod, {_, ok}, Acc, States) ->
{Acc, States};
Expand All @@ -34,6 +46,20 @@ do_send(Mod, {Id, {send, [{multicast, Msg}|T]}}, Acc, States) ->
do_send(_, Bleh, _, _) ->
erlang:error(Bleh).

set_timer(Id) ->
Timers = get_timers(),
erlang:put(timers, lists:usort([Id|Timers])).

cancel_timer(Id) ->
Timers = get_timers(),
erlang:put(timers, Timers -- [Id]).

get_timers() ->
case erlang:get(timers) of
undefined -> [];
R -> R
end.

random_n(N, List) ->
lists:sublist(shuffle(List), N).

Expand Down
1 change: 0 additions & 1 deletion test/dkg_worker.erl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ dispatch(Other, State) ->
do_send([], _) ->
ok;
do_send([{unicast, Dest, Msg}|T], State) ->
%io:format("~p unicasting ~p to ~p~n", [State#state.id, Msg, global:whereis_name(name(Dest))]),
gen_server:cast({global, name(Dest)}, {dkg, State#state.id, Msg}),
do_send(T, State);
do_send([{multicast, Msg}|T], State) ->
Expand Down

0 comments on commit 3b9b3a1

Please sign in to comment.