#ifndef _MAC_Check #define _MAC_Check /* Class for storing MAC Check data and doing the Check */ #include #include using namespace std; #include "Math/Share.h" #include "Networking/Player.h" #include "Networking/ServerSocket.h" #include "Auth/Summer.h" #include "Tools/time-func.h" /* The MAX number of things we will partially open before running * a MAC Check * * Keep this at much less than 1MB of data to be able to cope with * multi-threaded players * */ #define POPEN_MAX 1000000 template void write_mac_key(string& dir, int my_num, const T& key); template void read_mac_key(string& dir, int my_num, T& key); template class TreeSum { static const char* mc_timer_names[]; protected: int base_player; int opening_sum; int max_broadcast; octetStream os; void ReceiveValues(vector& values, const Player& P, int sender); virtual void AddToValues(vector& values) { (void)values; } virtual void GetValues(vector& values) { (void)values; } public: vector oss; vector timers; vector player_timers; TreeSum(int opening_sum = 10, int max_broadcast = 10, int base_player = 0); virtual ~TreeSum(); void start(vector& values, const Player& P); void finish(vector& values, const Player& P); void run(vector& values, const Player& P); octetStream& get_buffer() { return os; } size_t report_size(ReportType type); }; template class MAC_Check_Base { protected: /* MAC Share */ typename T::mac_key_type alphai; public: int values_opened; MAC_Check_Base() : values_opened(0) {} virtual ~MAC_Check_Base() {} virtual void Check(const Player& P) { (void)P; } int number() const { return values_opened; } const typename T::mac_key_type& get_alphai() const { return alphai; } virtual void POpen_Begin(vector& values,const vector& S,const Player& P) = 0; virtual void POpen_End(vector& values,const vector& S,const Player& P) = 0; void POpen(vector& values,const vector& S,const Player& P); typename T::open_type POpen(const T& secret, const Player& P); }; template class MAC_Check_ : public TreeSum, public MAC_Check_Base { typedef typename U::open_type T; protected: /* POpen Data */ int popen_cnt; vector macs; vector vals; virtual void AddToMacs(const vector& shares); virtual void PrepareSending(vector& values,const vector& S); void AddToValues(vector& values); void GetValues(vector& values); void CheckIfNeeded(const Player& P); int WaitingForCheck() { return max(macs.size(), vals.size()); } public: MAC_Check_(const T& ai, int opening_sum=10, int max_broadcast=10, int send_player=0); virtual ~MAC_Check_(); /* Run protocols to partially open data and check the MACs are * all OK. * - Implicit assume that the amount of data being sent does * not overload the OS * Begin and End expect the same arrays values and S passed to them * and they expect values to be of the same size as S. */ virtual void POpen_Begin(vector& values,const vector& S,const Player& P); virtual void POpen_End(vector& values,const vector& S,const Player& P); virtual void AddToCheck(const U& share, const T& value, const Player& P); virtual void Check(const Player& P); // compatibility void set_random_element(const U& random_element) { (void) random_element; } }; template using MAC_Check = MAC_Check_>; template class Spdz2kShare; template class Spdz2kPrep; template class MascotPrep; template class MAC_Check_Z2k : public MAC_Check_ { protected: vector shares; MascotPrep* prep; W get_random_element(); void AddToMacs(const vector< W >& shares); void PrepareSending(vector& values,const vector& S); public: vector random_elements; void AddToCheck(const W& share, const T& value, const Player& P); MAC_Check_Z2k(const T& ai, int opening_sum=10, int max_broadcast=10, int send_player=0); MAC_Check_Z2k(const T& ai, Names& Nms, int thread_num); virtual void Check(const Player& P); void set_random_element(const W& random_element); void set_prep(MascotPrep& prep); virtual ~MAC_Check_Z2k() {}; }; template void add_openings(vector& values, const Player& P, int sum_players, int last_sum_players, int send_player, TreeSum& MC); template class Separate_MAC_Check: public MAC_Check { // Different channel for checks PlainPlayer check_player; protected: // No sense to expose this Separate_MAC_Check(const T& ai, Names& Nms, int thread_num, int opening_sum=10, int max_broadcast=10, int send_player=0); virtual ~Separate_MAC_Check() {}; public: virtual void Check(const Player& P); }; template class Parallel_MAC_Check: public Separate_MAC_Check { // Different channel for every round PlainPlayer send_player; // Managed by Summer Player* receive_player; vector< Summer* > summers; int send_base_player; WaitQueue< vector > value_queue; public: Parallel_MAC_Check(const T& ai, Names& Nms, int thread_num, int opening_sum=10, int max_broadcast=10, int send_player=0); virtual ~Parallel_MAC_Check(); virtual void POpen_Begin(vector& values,const vector >& S,const Player& P); virtual void POpen_End(vector& values,const vector >& S,const Player& P); friend class Summer; }; template class Direct_MAC_Check: public Separate_MAC_Check { int open_counter; vector oss; public: Direct_MAC_Check(const T& ai, Names& Nms, int thread_num); ~Direct_MAC_Check(); void POpen_Begin(vector& values,const vector >& S,const Player& P); void POpen_End(vector& values,const vector >& S,const Player& P); }; template class Passing_MAC_Check : public Separate_MAC_Check { public: Passing_MAC_Check(const T& ai, Names& Nms, int thread_num); void POpen_Begin(vector& values,const vector >& S,const Player& P); void POpen_End(vector& values,const vector >& S,const Player& P); }; enum mc_timer { SEND, RECV_ADD, BCAST, RECV_SUM, SEED, COMMIT, WAIT_SUMMER, RECV, SUM, SELECT, MAX_TIMER }; template TreeSum::TreeSum(int opening_sum, int max_broadcast, int base_player) : base_player(base_player), opening_sum(opening_sum), max_broadcast(max_broadcast) { timers.resize(MAX_TIMER); } template TreeSum::~TreeSum() { #ifdef TREESUM_TIMINGS for (unsigned int i = 0; i < timers.size(); i++) if (timers[i].elapsed() > 0) cerr << T::type_string() << " " << mc_timer_names[i] << ": " << timers[i].elapsed() << endl; for (unsigned int i = 0; i < player_timers.size(); i++) if (player_timers[i].elapsed() > 0) cerr << T::type_string() << " waiting for " << i << ": " << player_timers[i].elapsed() << endl; #endif } template void TreeSum::run(vector& values, const Player& P) { start(values, P); finish(values, P); } template size_t TreeSum::report_size(ReportType type) { if (type == CAPACITY) return os.get_max_length(); else return os.get_length(); } template void add_openings(vector& values, const Player& P, int sum_players, int last_sum_players, int send_player, TreeSum& MC) { MC.player_timers.resize(P.num_players()); vector& oss = MC.oss; oss.resize(P.num_players()); vector senders; senders.reserve(P.num_players()); for (int relative_sender = positive_modulo(P.my_num() - send_player, P.num_players()) + sum_players; relative_sender < last_sum_players; relative_sender += sum_players) { int sender = positive_modulo(send_player + relative_sender, P.num_players()); senders.push_back(sender); } for (int j = 0; j < (int)senders.size(); j++) P.request_receive(senders[j], oss[j]); for (int j = 0; j < (int)senders.size(); j++) { int sender = senders[j]; MC.player_timers[sender].start(); P.wait_receive(sender, oss[j], true); MC.player_timers[sender].stop(); if ((unsigned)oss[j].get_length() < values.size() * T::size()) { stringstream ss; ss << "Not enough information received, expected " << values.size() * T::size() << " bytes, got " << oss[j].get_length(); throw Processor_Error(ss.str()); } MC.timers[SUM].start(); for (unsigned int i=0; i(oss[j]); } MC.timers[SUM].stop(); } } template void TreeSum::start(vector& values, const Player& P) { os.reset_write_head(); int sum_players = P.num_players(); int my_relative_num = positive_modulo(P.my_num() - base_player, P.num_players()); while (true) { int last_sum_players = sum_players; sum_players = (sum_players - 2 + opening_sum) / opening_sum; if (sum_players == 0) break; if (my_relative_num >= sum_players && my_relative_num < last_sum_players) { for (unsigned int i=0; i(values, P, sum_players, last_sum_players, base_player, *this); else add_openings(values, P, sum_players, last_sum_players, base_player, *this); timers[RECV_ADD].stop(); } } if (P.my_num() == base_player) { os.reset_write_head(); for (unsigned int i=0; i void TreeSum::finish(vector& values, const Player& P) { int my_relative_num = positive_modulo(P.my_num() - base_player, P.num_players()); if (my_relative_num * max_broadcast >= P.num_players()) { int sender = (base_player + my_relative_num / max_broadcast) % P.num_players(); ReceiveValues(values, P, sender); } else GetValues(values); } template void TreeSum::ReceiveValues(vector& values, const Player& P, int sender) { timers[RECV_SUM].start(); P.receive_player(sender, os, true); timers[RECV_SUM].stop(); for (unsigned int i = 0; i < values.size(); i++) values[i].unpack(os); AddToValues(values); } template string mac_key_filename(string& dir, int my_num) { return dir + "/Player-MAC-Key-" + T::type_string() + "-P" + to_string(my_num); } template void write_mac_key(string& dir, int my_num, const T& key) { string filename = mac_key_filename(dir, my_num); cout << "Writing to " << filename << endl; ofstream outf(filename); key.output(outf, false); if (not outf.good()) throw IO_Error(filename); } template T read_mac_key(string& dir, int my_num) { string filename = mac_key_filename(dir, my_num); cout << "Reading from " << filename << endl; T key; ifstream inpf(filename); key.input(inpf, false); if (not inpf.good()) throw IO_Error(filename); return key; } #endif