Skip to content

Commit

Permalink
Merge aa121d4 into f68df43
Browse files Browse the repository at this point in the history
  • Loading branch information
vihu committed May 1, 2018
2 parents f68df43 + aa121d4 commit c07aa62
Show file tree
Hide file tree
Showing 16 changed files with 560 additions and 179 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ _build
.idea
*.iml
rebar3.crashdump

*.html
*.css
*cache
ct_run.*
*.js
*nohost
157 changes: 116 additions & 41 deletions src/hbbft.erl

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions src/hbbft.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-record(hbbft_data, {
batch_size :: pos_integer(),
secret_key :: tpke_privkey:privkey(),
n :: pos_integer(),
f :: pos_integer(),
j :: non_neg_integer(),
round = 0 :: non_neg_integer(),
buf = [] :: [binary()],
acs :: hbbft_acs:acs_data(),
acs_init = false :: boolean(),
sent_txns = false :: boolean(),
sent_sig = false :: boolean(),
acs_results = [] :: [{non_neg_integer(), binary()}],
dec_shares = #{} :: #{non_neg_integer() => {non_neg_integer(), erlang_pbc:element()}},
decrypted = #{} :: #{non_neg_integer() => [binary()]},
sig_shares = #{} :: #{non_neg_integer() => {non_neg_integer(), erlang_pbc:element()}},
thingtosign :: undefined | erlang_pbc:element()
}).

-record(hbbft_serialized_data, {
batch_size :: pos_integer(),
n :: pos_integer(),
f :: pos_integer(),
j :: non_neg_integer(),
round = 0 :: non_neg_integer(),
buf = [] :: [binary()],
acs :: hbbft_acs:acs_serialized_data(),
acs_init = false :: boolean(),
sent_txns = false :: boolean(),
sent_sig = false :: boolean(),
acs_results = [] :: [{non_neg_integer(), binary()}],
decrypted = #{} :: #{non_neg_integer() => [binary()]},
sig_shares = #{} :: #{non_neg_integer() => {non_neg_integer(), binary()}},
dec_shares = #{} :: #{non_neg_integer() => {non_neg_integer(), binary()}},
thingtosign :: undefined | binary()
}).

80 changes: 49 additions & 31 deletions src/hbbft_acs.erl
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
-module(hbbft_acs).

-export([init/4, input/2, handle_msg/3]).

-record(rbc_state, {
rbc_data :: hbbft_rbc:rbc_data(),
result :: undefined | binary()
}).

-record(bba_state, {
bba_data :: hbbft_bba:bba_data(),
input :: undefined | 0 | 1,
result :: undefined | boolean()
}).

-record(acs_data, {
done = false :: boolean(),
n :: pos_integer(),
f :: non_neg_integer(),
j :: non_neg_integer(),
rbc = #{} :: #{non_neg_integer() => rbc_state()},
bba = #{} :: #{non_neg_integer() => bba_state()}
}).
-include_lib("hbbft_acs.hrl").

-export([init/4, input/2, handle_msg/3, serialize/1, deserialize/2]).

-type acs_data() :: #acs_data{}.
-type acs_serialized_data() :: #acs_serialized_data{}.
-type rbc_state() :: #rbc_state{}.
-type rbc_serialized_state() :: #rbc_serialized_state{}.
-type bba_state() :: #bba_state{}.
-type bba_serialized_state() :: #bba_serialized_state{}.

-type bba_msg() :: {{bba, non_neg_integer()}, hbbft_bba:msgs()}.
-type rbc_msg() :: {{rbc, non_neg_integer()}, hbbft_rbc:msgs()}.
-type rbc_wrapped_output() :: hbbft_utils:unicast({{rbc, non_neg_integer()}, hbbft_rbc:val_msg()}) | hbbft_utils:multicast({{rbc, non_neg_integer()}, hbbft_rbc:echo_msg() | hbbft_rbc:ready_msg()}).
-type msgs() :: bba_msg() | rbc_msg().

-export_type([acs_data/0, msgs/0, bba_msg/0]).
-export_type([acs_data/0, msgs/0, bba_msg/0, acs_serialized_data/0, bba_state/0, rbc_state/0, bba_serialized_state/0, rbc_serialized_state/0]).

-spec init(tpke_privkey:privkey(), pos_integer(), non_neg_integer(), non_neg_integer()) -> acs_data().
init(SK, N, F, J) ->
Expand All @@ -56,14 +41,12 @@ input(Data, Input) ->
{result, [{non_neg_integer(), binary()}]}}.
handle_msg(Data, J, {{rbc, I}, RBCMsg}) ->
RBC = get_rbc(Data, I),
io:format("~p RBC message for ~p ~p~n", [Data#acs_data.j, I, element(1, RBCMsg)]),
case hbbft_rbc:handle_msg(RBC#rbc_state.rbc_data, J, RBCMsg) of
{NewRBC, {send, ToSend}} ->
{store_rbc_state(Data, I, NewRBC), {send, hbbft_utils:wrap({rbc, I}, ToSend)}};
{NewRBC, {result, Result}} ->
%% Figure4, Bullet2
%% upon delivery of vj from RBCj, if input has not yet been provided to BAj, then provide input 1 to BAj
io:format("~p RBC returned for ~p~n", [Data#acs_data.j, I]),
NewData = store_rbc_result(store_rbc_state(Data, I, NewRBC), I, Result),
case bba_has_had_input(maps:get(I, Data#acs_data.bba)) of
true ->
Expand All @@ -84,22 +67,18 @@ handle_msg(Data = #acs_data{n=N, f=F}, J, {{bba, I}, BBAMsg}) ->
{NewBBA, {send, ToSend}} ->
{store_bba_state(Data, I, NewBBA), {send, hbbft_utils:wrap({bba, I}, ToSend)}};
{NewBBA, {result, B}} ->
io:format("~p BBA ~p returned ~p~n", [Data#acs_data.j, I, B]),
NewData = store_bba_state(store_bba_result(Data, I, B), I, NewBBA),
%% Figure4, Bullet3
%% upon delivery of value 1 from at least N − f instances of BA , provide input 0 to each instance of BA that has not yet been provided input.
BBAsThatReturnedOne = successful_bba_count(NewData),
io:format("~p ~p BBAs completed, ~p returned one, ~p needed~n", [Data#acs_data.j, completed_bba_count(NewData), BBAsThatReturnedOne, N - F]),
case BBAsThatReturnedOne >= N - F andalso NewData#acs_data.done == false of
true ->
io:format("~b Enough BBAs (~b/~b) completed, zeroing the rest~n", [Data#acs_data.j, BBAsThatReturnedOne, N]),
%% send 0 to all BBAs that have not yet been provided input because their RBC has not completed
{NextData, Replies} = lists:foldl(fun(E, {DataAcc, MsgAcc}=Acc) ->
ThisBBA = get_bba(DataAcc, E),
case bba_has_had_input(ThisBBA) of
false ->
{FailedBBA, {send, ToSend}} = hbbft_bba:input(ThisBBA#bba_state.bba_data, 0),
io:format("~p Sending BBA ~p zero~n", [Data#acs_data.j, E]),
{store_bba_input(store_bba_state(Data, E, FailedBBA), E, 0), [hbbft_utils:wrap({bba, E}, ToSend)|MsgAcc]};
true ->
Acc
Expand Down Expand Up @@ -139,9 +118,10 @@ bba_completed(#bba_state{input=Input, result=Result}) ->
successful_bba_count(Data) ->
lists:sum([ 1 || BBA <- maps:values(Data#acs_data.bba), BBA#bba_state.result]).

-spec completed_bba_count(acs_data()) -> non_neg_integer(). %% completed_bba_count cannot be 0
completed_bba_count(Data) ->
lists:sum([ 1 || BBA <- maps:values(Data#acs_data.bba), BBA#bba_state.result /= undefined]).
%% XXX: Unused function, remove?
%% -spec completed_bba_count(acs_data()) -> non_neg_integer(). %% completed_bba_count cannot be 0
%% completed_bba_count(Data) ->
%% lists:sum([ 1 || BBA <- maps:values(Data#acs_data.bba), BBA#bba_state.result /= undefined]).

-spec get_bba(acs_data(), non_neg_integer()) -> bba_state().
get_bba(Data, I) ->
Expand Down Expand Up @@ -190,6 +170,44 @@ store_rbc_result(Data, I, Result) ->
RBC = get_rbc(Data, I),
Data#acs_data{rbc = maps:put(I, RBC#rbc_state{result=Result}, Data#acs_data.rbc)}.

-spec serialize(acs_data()) -> acs_serialized_data().
serialize(#acs_data{done=Done, n=N, f=F, j=J, rbc=RBCMap, bba=BBAMap}) ->
#acs_serialized_data{done=Done, n=N, f=F, j=J, rbc=serialize_state(RBCMap, rbc), bba=serialize_state(BBAMap, bba)}.

-spec deserialize(acs_serialized_data(), tpke_privkey:privkey()) -> acs_data().
deserialize(#acs_serialized_data{done=Done, n=N, f=F, j=J, rbc=RBCMap, bba=BBAMap}, SK) ->
#acs_data{done=Done, n=N, f=F, j=J, rbc=deserialize_state(RBCMap, rbc), bba=deserialize_state(BBAMap, bba, SK)}.

%% Helper functions for serialization/deserialization
-spec serialize_state(#{non_neg_integer() => rbc_state() | bba_state()}, rbc | bba) -> #{}.
serialize_state(State, rbc) ->
maps:map(fun(_K, V) -> serialize_rbc_state(V) end, State);
serialize_state(State, bba) ->
maps:map(fun(_K, V) -> serialize_bba_state(V) end, State).

-spec deserialize_state(#{non_neg_integer() => rbc_serialized_state()}, rbc) -> #{}.
deserialize_state(State, rbc) ->
maps:map(fun(_K, V) -> deserialize_rbc_state(V) end, State).

-spec deserialize_state(#{non_neg_integer() => bba_serialized_state()}, bba, tpke_privkey:privkey()) -> #{}.
deserialize_state(State, bba, SK) ->
maps:map(fun(_K, V) -> deserialize_bba_state(V, SK) end, State).

-spec serialize_rbc_state(rbc_state()) -> rbc_serialized_state().
serialize_rbc_state(#rbc_state{rbc_data=RBCData, result=Result}) ->
#rbc_serialized_state{rbc_data=RBCData, result=Result}.

-spec deserialize_rbc_state(rbc_serialized_state()) -> rbc_state().
deserialize_rbc_state(#rbc_serialized_state{rbc_data=RBCData, result=Result}) ->
#rbc_state{rbc_data=RBCData, result=Result}.

-spec serialize_bba_state(bba_state()) -> bba_serialized_state().
serialize_bba_state(#bba_state{bba_data=BBAData, input=Input, result=Result}) ->
#bba_serialized_state{bba_data=hbbft_bba:serialize(BBAData), input=Input, result=Result}.

-spec deserialize_bba_state(bba_serialized_state(), tpke_privkey:privkey()) -> bba_state().
deserialize_bba_state(#bba_serialized_state{bba_data=BBAData, input=Input, result=Result}, SK) ->
#bba_state{bba_data=hbbft_bba:deserialize(BBAData, SK), input=Input, result=Result}.

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
Expand Down
39 changes: 39 additions & 0 deletions src/hbbft_acs.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
-record(rbc_state, {
rbc_data :: hbbft_rbc:rbc_data(),
result :: undefined | binary()
}).

-record(bba_state, {
bba_data :: hbbft_bba:bba_data(),
input :: undefined | 0 | 1,
result :: undefined | boolean()
}).

-record(acs_data, {
done = false :: boolean(),
n :: pos_integer(),
f :: non_neg_integer(),
j :: non_neg_integer(),
rbc = #{} :: #{non_neg_integer() => hbbft_acs:rbc_state()},
bba = #{} :: #{non_neg_integer() => hbbft_acs:bba_state()}
}).

-record(acs_serialized_data, {
done = false :: boolean(),
n :: pos_integer(),
f :: non_neg_integer(),
j :: non_neg_integer(),
rbc = #{} :: #{non_neg_integer() => hbbft_acs:rbc_serialized_state()},
bba = #{} :: #{non_neg_integer() => hbbft_acs:bba_serialized_state()}
}).

-record(rbc_serialized_state, {
rbc_data :: hbbft_rbc:rbc_data(),
result :: undefined | binary()
}).

-record(bba_serialized_state, {
bba_data :: hbbft_bba:bba_serialized_data(),
input :: undefined | 0 | 1,
result :: undefined | boolean()
}).
107 changes: 75 additions & 32 deletions src/hbbft_bba.erl
Original file line number Diff line number Diff line change
@@ -1,33 +1,18 @@
-module(hbbft_bba).

-export([init/3, input/2, handle_msg/3]).
-include_lib("hbbft_bba.hrl").

-record(bba_data, {
state = init :: init | waiting | done,
round = 0 :: non_neg_integer(),
secret_key :: tpke_privkey:privkey(),
coin :: undefined | hbbft_cc:cc_data(),
est :: undefined | 0 | 1,
output :: undefined | 0 | 1,
f :: non_neg_integer(),
n :: pos_integer(),
witness = maps:new() :: #{non_neg_integer() => 0 | 1},
aux_witness = maps:new() :: #{non_neg_integer() => 0 | 1},
aux_sent = false :: boolean(),
%% Sets take relatively large space
%% using bit values here serve the same purpose while saving us space
broadcasted = 00 :: 0 | 1 | 2 | 3,
bin_values = 00 :: 0 | 1 | 2 | 3
}).
-export([init/3, input/2, handle_msg/3, serialize/1, deserialize/2]).

-type bba_data() :: #bba_data{}.
-type bba_serialized_data() :: #bba_serialized_data{}.

-type bval_msg() :: {bval, non_neg_integer(), 0 | 1}.
-type aux_msg() :: {aux, non_neg_integer(), 0 | 1}.
-type coin_msg() :: {{coin, non_neg_integer()}, hbbft_cc:share_msg()}.
-type msgs() :: bval_msg() | aux_msg() | coin_msg().

-export_type([bba_data/0, bval_msg/0, aux_msg/0, coin_msg/0, msgs/0]).
-export_type([bba_data/0, bba_serialized_data/0, bval_msg/0, aux_msg/0, coin_msg/0, msgs/0]).

-spec init(tpke_privkey:privkey(), pos_integer(), non_neg_integer()) -> bba_data().
init(SK, N, F) ->
Expand Down Expand Up @@ -153,24 +138,88 @@ aux(Data = #bba_data{n=N, f=F}, Id, V) ->
{NewData, ok}
end.

-spec serialize(bba_data()) -> bba_serialized_data().
serialize(#bba_data{state=State,
round=Round,
coin=Coin,
est=Est,
output=Output,
f=F,
n=N,
witness=Witness,
aux_witness=AuxWitness,
aux_sent=AuxSent,
broadcasted=Broadcasted,
bin_values=BinValues}) ->
NewCoin = case Coin of
undefined -> undefined;
_ -> hbbft_cc:serialize(Coin)
end,
#bba_serialized_data{state=State,
round=Round,
coin=NewCoin,
est=Est,
output=Output,
f=F,
n=N,
witness=Witness,
aux_witness=AuxWitness,
aux_sent=AuxSent,
broadcasted=Broadcasted,
bin_values=BinValues}.


-spec deserialize(bba_serialized_data(), tpke_privkey:privkey()) -> bba_data().
deserialize(#bba_serialized_data{state=State,
round=Round,
coin=Coin,
est=Est,
output=Output,
f=F,
n=N,
witness=Witness,
aux_witness=AuxWitness,
aux_sent=AuxSent,
broadcasted=Broadcasted,
bin_values=BinValues}, SK) ->
NewCoin = case Coin of
undefined -> undefined;
_ -> hbbft_cc:deserialize(Coin, SK)
end,
#bba_data{state=State,
secret_key=SK,
round=Round,
coin=NewCoin,
est=Est,
output=Output,
f=F,
n=N,
witness=Witness,
aux_witness=AuxWitness,
aux_sent=AuxSent,
broadcasted=Broadcasted,
bin_values=BinValues}.


%% helper functions
-spec check_n_minus_f_aux_messages(pos_integer(), non_neg_integer(), bba_data()) -> boolean().
check_n_minus_f_aux_messages(N, F, Data) ->
%% check if we've received at least N - F AUX messages where the values in the AUX messages are member of bin_values
maps:size(maps:filter(fun(_, X) -> has(X, Data#bba_data.bin_values) end, Data#bba_data.aux_witness)) >= N - F.
maps:fold(fun(_, V, Acc) ->
case has(V, Data#bba_data.bin_values) of
true ->
Acc + 1;
false -> Acc
end
end, 0, Data#bba_data.aux_witness) >= N - F.

%% add X to set Y
add(X, Y) ->
Res = (1 bsl X) bor Y,
io:format("Added ~.2b to ~.2b -> ~.2b~n", [1 bsl X, Y, Res]),
Res.
(1 bsl X) bor Y.

%% is X in set Y?
has(X, Y) ->
Res = ((1 bsl X) band Y) /= 0,
io:format("Checked if ~.2b is in ~.2b -> ~p~n", [1 bsl X, Y, Res]),
Res.
((1 bsl X) band Y) /= 0.

%% count elements of set
count(2#0) -> 0;
Expand Down Expand Up @@ -205,7 +254,6 @@ init_test() ->
end, StatesWithId),
{NewStates, Results} = lists:unzip(Res),
{_, ConvergedResults} = hbbft_test_utils:do_send_outer(?MODULE, Results, NewStates, sets:new()),
io:format("ConvergedResults ~p~n", [ConvergedResults]),
%% everyone should converge
?assertEqual(N, sets:size(ConvergedResults)),
ok.
Expand All @@ -227,7 +275,6 @@ init_with_zeroes_test() ->
{NewStates, Results} = lists:unzip(Res),
{_, ConvergedResults} = hbbft_test_utils:do_send_outer(?MODULE, Results, NewStates, sets:new()),
DistinctResults = sets:from_list([BVal || {result, {_, BVal}} <- sets:to_list(ConvergedResults)]),
io:format("DistinctResults: ~p~n", [sets:to_list(DistinctResults)]),
?assertEqual(N, sets:size(ConvergedResults)),
?assertEqual([0], sets:to_list(DistinctResults)),
ok.
Expand All @@ -249,8 +296,6 @@ init_with_ones_test() ->
{NewStates, Results} = lists:unzip(Res),
{_, ConvergedResults} = hbbft_test_utils:do_send_outer(?MODULE, Results, NewStates, sets:new()),
DistinctResults = sets:from_list([BVal || {result, {_, BVal}} <- sets:to_list(ConvergedResults)]),
io:format("DistinctResults: ~p~n", [sets:to_list(DistinctResults)]),
%% io:format("ConvergedResults ~p~n", [ConvergedResults]),
?assertEqual(N, sets:size(ConvergedResults)),
?assertEqual([1], sets:to_list(DistinctResults)),
ok.
Expand All @@ -273,8 +318,6 @@ init_with_mixed_zeros_and_ones_test_() ->
{NewStates, Results} = lists:unzip(Res),
{_, ConvergedResults} = hbbft_test_utils:do_send_outer(?MODULE, Results, NewStates, sets:new()),
DistinctResults = sets:from_list([BVal || {result, {_, BVal}} <- sets:to_list(ConvergedResults)]),
io:format("DistinctResults: ~p~n", [sets:to_list(DistinctResults)]),
io:format("ConvergedResults ~p~n", [sets:to_list(ConvergedResults)]),
?assertEqual(N, sets:size(ConvergedResults)),
?assertEqual(1, sets:size(DistinctResults)),
ok
Expand Down
Loading

0 comments on commit c07aa62

Please sign in to comment.