diff --git a/.gitignore b/.gitignore index 56bffa619..1660f528c 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ Programs/Public-Input/* *.static *.d local/ +*.map # Packages # ############ diff --git a/Auth/MAC_Check.h b/Auth/MAC_Check.h index 84de474ed..57b15be12 100644 --- a/Auth/MAC_Check.h +++ b/Auth/MAC_Check.h @@ -24,9 +24,17 @@ using namespace std; #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; @@ -60,7 +68,7 @@ class MAC_Check_Base { protected: /* MAC Share */ - typename T::clear alphai; + typename T::mac_key_type alphai; public: int values_opened; @@ -72,26 +80,29 @@ class MAC_Check_Base int number() const { return values_opened; } - const typename T::clear& get_alphai() const { return alphai; } + 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::clear POpen(const T& secret, const Player& P); + 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> +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 macs; vector vals; - void AddToMacs(const vector< Share >& shares); + 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); @@ -100,8 +111,8 @@ class MAC_Check : public TreeSum, public MAC_Check_Base> public: - MAC_Check(const T& ai, int opening_sum=10, int max_broadcast=10, int send_player=0); - virtual ~MAC_Check(); + 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. @@ -110,11 +121,45 @@ class MAC_Check : public TreeSum, public MAC_Check_Base> * 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 POpen_Begin(vector& values,const vector& S,const Player& P); + virtual void POpen_End(vector& values,const vector& S,const Player& P); - void AddToCheck(const T& mac, const T& value, 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() {}; }; @@ -359,4 +404,34 @@ void TreeSum::ReceiveValues(vector& values, const Player& P, int sender) 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 diff --git a/Auth/MAC_Check.cpp b/Auth/MAC_Check.hpp similarity index 66% rename from Auth/MAC_Check.cpp rename to Auth/MAC_Check.hpp index 5a7cb5064..d01b2c8e9 100644 --- a/Auth/MAC_Check.cpp +++ b/Auth/MAC_Check.hpp @@ -6,6 +6,7 @@ #include "Tools/random.h" #include "Tools/time-func.h" #include "Tools/int.h" +#include "Tools/benchmarking.h" #include "Math/gfp.h" #include "Math/gf2n.h" @@ -14,10 +15,13 @@ #include "Math/MaliciousRep3Share.h" #include "Math/ShamirShare.h" #include "Math/MaliciousShamirShare.h" +#include "Math/Z2k.h" +#include "Math/Spdz2kShare.h" #include -const char* mc_timer_names[] = { +template +const char* TreeSum::mc_timer_names[] = { "sending", "receiving and adding", "broadcasting", @@ -30,8 +34,8 @@ const char* mc_timer_names[] = { "waiting for select()" }; -template -MAC_Check::MAC_Check(const T& ai, int opening_sum, int max_broadcast, int send_player) : +template +MAC_Check_::MAC_Check_(const T& ai, int opening_sum, int max_broadcast, int send_player) : TreeSum(opening_sum, max_broadcast, send_player) { popen_cnt=0; @@ -41,26 +45,32 @@ MAC_Check::MAC_Check(const T& ai, int opening_sum, int max_broadcast, int sen } template -MAC_Check::~MAC_Check() +MAC_Check_::~MAC_Check_() { } -template -void MAC_Check::POpen_Begin(vector& values,const vector >& S,const Player& P) +template +void MAC_Check_::PrepareSending(vector& values, const vector& S) { - AddToMacs(S); - values.resize(S.size()); for (unsigned int i=0; i +void MAC_Check_::POpen_Begin(vector& values,const vector& S,const Player& P) +{ + AddToMacs(S); + + PrepareSending(values, S); this->start(values, P); this->values_opened += S.size(); } -template -void MAC_Check::POpen_End(vector& values,const vector >& S,const Player& P) +template +void MAC_Check_::POpen_End(vector& values,const vector& S,const Player& P) { S.size(); @@ -77,37 +87,42 @@ void MAC_Check::POpen_End(vector& values,const vector >& S,const } template -void MAC_Check_Base::POpen(vector& values,const vector& S,const Player& P) +void MAC_Check_Base::POpen(vector& values,const vector& S,const Player& P) { POpen_Begin(values, S, P); POpen_End(values, S, P); } template -typename T::clear MAC_Check_Base::POpen(const T& secret, const Player& P) +typename T::open_type MAC_Check_Base::POpen(const T& secret, const Player& P) { - vector opened; + vector opened; POpen(opened, {secret}, P); return opened[0]; } -template -void MAC_Check::AddToMacs(const vector >& shares) +template +void MAC_Check_::AddToMacs(const vector& shares) { for (unsigned int i = 0; i < shares.size(); i++) macs.push_back(shares[i].get_mac()); +#ifdef DEBUG_MAC + if (shares.size()) + cout << "adding macs " << shares.back() << " / " << + shares.back().get_mac() << " / " << macs.back() << endl; +#endif } -template -void MAC_Check::AddToValues(vector& values) +template +void MAC_Check_::AddToValues(vector& values) { vals.insert(vals.end(), values.begin(), values.end()); } -template -void MAC_Check::GetValues(vector& values) +template +void MAC_Check_::GetValues(vector& values) { int size = values.size(); if (popen_cnt + size > int(vals.size())) @@ -123,17 +138,17 @@ void MAC_Check::GetValues(vector& values) template -void MAC_Check::CheckIfNeeded(const Player& P) +void MAC_Check_::CheckIfNeeded(const Player& P) { if (WaitingForCheck() >= POPEN_MAX) Check(P); } -template -void MAC_Check::AddToCheck(const T& mac, const T& value, const Player& P) +template +void MAC_Check_::AddToCheck(const U& share, const T& value, const Player& P) { - macs.push_back(mac); + macs.push_back(share.get_mac()); vals.push_back(value); popen_cnt++; CheckIfNeeded(P); @@ -141,8 +156,8 @@ void MAC_Check::AddToCheck(const T& mac, const T& value, const Player& P) -template -void MAC_Check::Check(const Player& P) +template +void MAC_Check_::Check(const Player& P) { if (WaitingForCheck() == 0) return; @@ -155,7 +170,7 @@ void MAC_Check::Check(const Player& P) PRNG G; G.SetSeed(seed); - Share sj; + U sj; T a,gami,h,temp; a.assign_zero(); gami.assign_zero(); @@ -195,6 +210,149 @@ int mc_base_id(int function_id, int thread_num) return (function_id << 28) + ((T::field_type() + 1) << 24) + (thread_num << 16); } +template +MAC_Check_Z2k::MAC_Check_Z2k(const T& ai, int opening_sum, int max_broadcast, int send_player) : + MAC_Check_(ai, opening_sum, max_broadcast, send_player), prep(0) +{ +} + +template +MAC_Check_Z2k::MAC_Check_Z2k(const T& ai, Names& Nms, + int thread_num) : MAC_Check_Z2k(ai) +{ + (void) Nms, (void) thread_num; +} + +template +void MAC_Check_Z2k::AddToCheck(const W& share, const T& value, const Player& P) +{ + shares.push_back(share.get_share()); + MAC_Check_::AddToCheck(share, value, P); +} + +template +void MAC_Check_Z2k::AddToMacs(const vector& shares) +{ + for (auto& share : shares) + this->shares.push_back(share.get_share()); + MAC_Check_::AddToMacs(shares); +#ifdef DEBUG_MAC + cout << "add share " << shares.back() << " / " << this->shares.back() << endl; +#endif +} + +template +void MAC_Check_Z2k::PrepareSending(vector& values, + const vector& S) +{ + values.clear(); + values.reserve(S.size()); + for (auto& share : S) + values.push_back(V(share.get_share())); +} + +template +W MAC_Check_Z2k::get_random_element() { + if (random_elements.size() > 0) + { + W res = random_elements.back(); + random_elements.pop_back(); + return res; + } + else + { + if (prep) + return prep->get_random(); + else + { + insecure("random dummy"); + return {}; + } + } +} + +template +void MAC_Check_Z2k::set_random_element(const W& random_element) { + random_elements.push_back(random_element); +} + +template +void MAC_Check_Z2k::set_prep(MascotPrep& prep) +{ + this->prep = &prep; +} + +template +void MAC_Check_Z2k::Check(const Player& P) +{ + if (this->WaitingForCheck() == 0) + return; + +#ifdef DEBUG_MAC + cout << "Checking " << shares[0] << " " << this->vals[0] << " " << this->macs[0] << endl; +#endif + + int k = V::N_BITS; + octet seed[SEED_SIZE]; + Create_Random_Seed(seed,P,SEED_SIZE); + PRNG G; + G.SetSeed(seed); + + T y, mj; + y.assign_zero(); + mj.assign_zero(); + vector chi; + for (int i = 0; i < this->popen_cnt; ++i) + { + U temp_chi; + temp_chi.randomize(G); + T xi = this->vals[i]; + y += xi * temp_chi; + T mji = this->macs[i]; + mj += temp_chi * mji; + chi.push_back(temp_chi); + } + + W r = get_random_element(); + T lj = r.get_mac(); + U pj; + pj.assign_zero(); + for (int i = 0; i < this->popen_cnt; ++i) + { + T xji = shares[i]; + V xbarji = xji; + U pji = U((xji - xbarji) >> k); + pj += chi[i] * pji; + } + pj += U(r.get_share()); + + U pbar(pj); + vector pj_stream(P.num_players()); + pj.pack(pj_stream[P.my_num()]); + P.Broadcast_Receive(pj_stream, true); + for (int j=0; jalphai * y) - (((this->alphai * pbar)) << k) + (lj << k); + vector zjs(P.num_players()); + zjs[P.my_num()] = zj; + Commit_And_Open(zjs, P); + + T zj_sum; + zj_sum.assign_zero(); + for (int i = 0; i < P.num_players(); ++i) + zj_sum += zjs[i]; + + this->vals.erase(this->vals.begin(), this->vals.begin() + this->popen_cnt); + this->macs.erase(this->macs.begin(), this->macs.begin() + this->popen_cnt); + this->shares.erase(this->shares.begin(), this->shares.begin() + this->popen_cnt); + this->popen_cnt=0; + if (!zj_sum.is_zero()) { throw mac_fail(); } +} + template Separate_MAC_Check::Separate_MAC_Check(const T& ai, Names& Nms, int thread_num, int opening_sum, int max_broadcast, int send_player) : @@ -439,32 +597,3 @@ void Passing_MAC_Check::POpen_End(vector& values,const vector >& this->popen_cnt += values.size(); this->CheckIfNeeded(P); } - -template class MAC_Check; -template class Direct_MAC_Check; -template class Parallel_MAC_Check; -template class Passing_MAC_Check; - -template class MAC_Check; -template class Direct_MAC_Check; -template class Parallel_MAC_Check; -template class Passing_MAC_Check; - -#ifdef USE_GF2N_LONG -template class MAC_Check; -template class Direct_MAC_Check; -template class Parallel_MAC_Check; -template class Passing_MAC_Check; -#endif - -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; -template class MAC_Check_Base>; diff --git a/Auth/Subroutines.cpp b/Auth/Subroutines.cpp index e76c92277..0f3a03674 100644 --- a/Auth/Subroutines.cpp +++ b/Auth/Subroutines.cpp @@ -4,6 +4,7 @@ #include "Tools/random.h" #include "Exceptions/Exceptions.h" #include "Tools/Commit.h" +#include "Math/Z2k.h" /* To ease readability as I re-write this program the following conventions * will be used. @@ -176,24 +177,20 @@ void Create_Random_Seed(octet* seed,const Player& P,int len) } -template -void Commit_And_Open(vector& data,const Player& P) +void Commit_And_Open_(vector& datas,const Player& P) { vector Comm_data(P.num_players()); vector Open_data(P.num_players()); - octetStream ee; - data[P.my_num()].pack(ee); - Commit(Comm_data[P.my_num()],Open_data[P.my_num()],ee,P.my_num()); + Commit(Comm_data[P.my_num()],Open_data[P.my_num()],datas[P.my_num()],P.my_num()); P.Broadcast_Receive(Comm_data); P.Broadcast_Receive(Open_data); for (int i = 0; i < P.num_players(); i++) { if (i != P.my_num()) - { if (!Open(ee,Comm_data[i],Open_data[i],i)) + { if (!Open(datas[i],Comm_data[i],Open_data[i],i)) { throw invalid_commitment(); } - data[i].unpack(ee); } } } @@ -232,13 +229,10 @@ void generate_challenge(vector& challenge, const Player& P) -template void Commit_And_Open(vector& data,const Player& P); template void Create_Random(gf2n& ans,const Player& P); #ifdef USE_GF2N_LONG -template void Commit_And_Open(vector& data,const Player& P); template void Create_Random(gf2n_short& ans,const Player& P); #endif -template void Commit_And_Open(vector& data,const Player& P); template void Create_Random(gfp& ans,const Player& P); diff --git a/Auth/Subroutines.h b/Auth/Subroutines.h index 2830d3426..e471a7390 100644 --- a/Auth/Subroutines.h +++ b/Auth/Subroutines.h @@ -46,6 +46,19 @@ void Commit_And_Open(vector< vector >& data,const Player& P,int num_runs); template void Commit_And_Open(vector& data,const Player& P); +void Commit_And_Open_(vector& datas,const Player& P); + +template +void Commit_And_Open(vector& data,const Player& P) +{ + vector datas(P.num_players()); + data[P.my_num()].pack(datas[P.my_num()]); + Commit_And_Open_(datas, P); + for (int i = 0; i < P.num_players(); i++) + data[i].unpack(datas[i]); +} + + template void Transmit_Data(vector< vector >& data,const Player& P,int num_runs); diff --git a/Auth/fake-stuff.h b/Auth/fake-stuff.h index 53bcc6b35..e4af6c82c 100644 --- a/Auth/fake-stuff.h +++ b/Auth/fake-stuff.h @@ -4,6 +4,7 @@ #include "Math/gf2n.h" #include "Math/gfp.h" +#include "Math/Z2k.h" #include "Math/Share.h" #include "Math/Rep3Share.h" #include "GC/MaliciousRepSecret.h" @@ -11,20 +12,22 @@ #include using namespace std; -template -void make_share(vector >& Sa,const T& a,int N,const T& key,PRNG& G); - -template -void check_share(vector >& Sa,T& value,T& mac,int N,const T& key); template void check_share(vector& Sa, typename T::clear& value, typename T::value_type& mac, int N, const typename T::value_type& key); +template +void check_share(vector >& Sa, + V& value, + T& mac, + int N, + const T& key); + // Generate MAC key shares void generate_keys(const string& directory, int nplayers); -template -void write_mac_keys(const string& directory, int player_num, int nplayers, gfp keyp, T key2); +template +void write_mac_keys(const string& directory, int player_num, int nplayers, U keyp, T key2); // Read MAC key shares and compute keys void read_keys(const string& directory, gfp& keyp, gf2n& key2, int nplayers); @@ -35,9 +38,9 @@ class Files public: ofstream* outf; int N; - typename T::value_type key; + typename T::mac_type key; PRNG G; - Files(int N, const typename T::value_type& key, const string& prefix) : N(N), key(key) + Files(int N, const typename T::mac_type& key, const string& prefix) : N(N), key(key) { outf = new ofstream[N]; for (int i=0; i -template -void make_share(vector >& Sa,const T& a,int N,const T& key,PRNG& G) +template +void make_share(Share* Sa,const U& a,int N,const V& key,PRNG& G) { insecure("share generation", false); T mac,x,y; @@ -18,7 +19,6 @@ void make_share(vector >& Sa,const T& a,int N,const T& key,PRNG& G) S.set_share(a); S.set_mac(mac); - Sa.resize(N); for (int i=0; i >& Sa,const T& a,int N,const T& key,PRNG& G) } template -void make_share(FixedVec* Sa, const T& a, int N, PRNG& G); +void make_share(FixedVec* Sa, const T& a, int N, const T& key, PRNG& G); template inline void make_share(vector& Sa, - const typename T::clear& a, int N, const typename T::value_type& key, + const typename T::clear& a, int N, const typename T::mac_type& key, PRNG& G) { - (void)key; Sa.resize(N); - make_share(Sa.data(), a, N, G); + make_share(Sa.data(), a, N, key, G); } template -void make_share(FixedVec* Sa, const T& a, int N, PRNG& G) +void make_share(FixedVec* Sa, const T& a, int N, const T& key, PRNG& G) { + (void) key; assert(N == 3); insecure("share generation", false); FixedVec add_shares; @@ -59,8 +59,12 @@ void make_share(FixedVec* Sa, const T& a, int N, PRNG& G) } } -template -void check_share(vector >& Sa,T& value,T& mac,int N,const T& key) +template +void check_share(vector >& Sa, + V& value, + T& mac, + int N, + const T& key) { value.assign(0); mac.assign(0); @@ -71,9 +75,9 @@ void check_share(vector >& Sa,T& value,T& mac,int N,const T& key) mac.add(Sa[i].get_mac()); } - T res; + V res; res.mul(value, key); - if (!res.equal(mac)) + if (res != mac) { cout << "Value: " << value << endl; cout << "Input MAC: " << mac << endl; @@ -134,8 +138,8 @@ inline string mac_filename(string directory, int playerno) return directory + "/Player-MAC-Keys-P" + to_string(playerno); } -template -void write_mac_keys(const string& directory, int i, int nplayers, gfp macp, T mac2) +template +void write_mac_keys(const string& directory, int i, int nplayers, U macp, T mac2) { ofstream outf; stringstream filename; diff --git a/BMR/Party.cpp b/BMR/Party.cpp index 072e72896..50d0d9806 100644 --- a/BMR/Party.cpp +++ b/BMR/Party.cpp @@ -19,6 +19,8 @@ #include "BooleanCircuit.h" #include "Math/Setup.h" +#include "Auth/MAC_Check.hpp" + #ifdef __PURE_SHE__ #include "mpirxx.h" #endif diff --git a/BMR/TrustedParty.cpp b/BMR/TrustedParty.cpp index 7ecefd27f..431cae27b 100644 --- a/BMR/TrustedParty.cpp +++ b/BMR/TrustedParty.cpp @@ -409,7 +409,7 @@ void TrustedProgramParty::garble() second_phase(program, processor, machine); vector< Share > tmp; - make_share(tmp, 1, get_n_parties(), mac_key, prng); + make_share(tmp, 1, get_n_parties(), mac_key, prng); for (int i = 0; i < get_n_parties(); i++) tmp[i].get_mac().pack(spdz_wires[SPDZ_MAC][i]); for (int i = 0; i < get_n_parties(); i++) diff --git a/CONFIG b/CONFIG index 5d675c6e1..b7b3f8bab 100644 --- a/CONFIG +++ b/CONFIG @@ -27,7 +27,7 @@ ARCH = -mtune=native -msse4.1 -maes -mpclmul -mavx -mavx2 -mbmi2 # allow to set compiler in CONFIG.mine CXX = g++ -#use CONFIG.mine to overwrite DIR settings +# use CONFIG.mine to overwrite DIR settings -include CONFIG.mine ifeq ($(USE_GF2N_LONG),1) diff --git a/Check-Offline-Z2k.cpp b/Check-Offline-Z2k.cpp new file mode 100644 index 000000000..1dcbc914a --- /dev/null +++ b/Check-Offline-Z2k.cpp @@ -0,0 +1,120 @@ + +#include "Math/Z2k.h" +#include "Math/Share.h" +#include "Math/Setup.h" +#include "Math/Spdz2kShare.h" +#include "Auth/fake-stuff.h" + +#include "Auth/fake-stuff.hpp" + +#include +#include +#include + +template +void check_triples_Z2k(int n_players, string type_char = "") +{ + typedef typename W::open_type T; + typedef typename W::mac_key_type U; + typedef typename W::open_type V; + + T keyp; keyp.assign_zero(); + U pp; + ifstream inpf; + for (int i= 0; i < n_players; i++) + { + stringstream ss; + ss << get_prep_dir(n_players, 128, 128) << "Player-MAC-Keys"; + ss << "-P" << i; + cout << "Opening file " << ss.str() << endl; + inpf.open(ss.str().c_str()); + if (inpf.fail()) { throw file_error(ss.str()); } + int n; + inpf >> n; + assert(n == n_players); + pp.input(inpf,true); + cout << " Key " << i << "\t p: " << pp << endl; + keyp.add(pp); + inpf.close(); + } + cout << "--------------\n"; + cout << "Final Keys :\t p: " << keyp << endl; + + ifstream* inputFiles = new ifstream[n_players]; + for (int i = 0; i < n_players; i++) + { + stringstream ss; + ss << get_prep_dir(n_players, 128, 128) << "Triples-"; + if (type_char.size()) + ss << type_char; + else + ss << W::type_short(); + ss << "-P" << i; + inputFiles[i].open(ss.str().c_str()); + cout << "Opening file " << ss.str() << endl; + } + + int j = 0; + while (inputFiles[0].peek() != EOF) + { + V a,b,c,prod; + T mac; + vector> as(n_players), bs(n_players), cs(n_players); + + for (int i = 0; i < n_players; i++) + { + as[i].input(inputFiles[i], false); + bs[i].input(inputFiles[i], false); + cs[i].input(inputFiles[i], false); + } + + check_share(as, a, mac, n_players, keyp); + check_share(bs, b, mac, n_players, keyp); + check_share(cs, c, mac, n_players, keyp); + + prod.mul(a, b); + if (prod != c) + { + cout << j << ": " << c << " != " << a << " * " << b << endl; + throw bad_value(); + } + j++; + } + + cout << dec << j << " correct triples of type " << T::type_string() << endl; + delete[] inputFiles; +} + +template +void check(int n_players) +{ + check_triples_Z2k>(n_players); +} + +int main(int argc, char** argv) +{ + int n_players = 2; + if (argc > 1) + n_players = atoi(argv[1]); + int k = 64; + if (argc > 2) + { + k = atoi(argv[2]); + } + int s = k; + if (argc > 3) + s = atoi(argv[3]); + + if (k == 32) + check<32, 32>(n_players); + else if (k == 64 and s == 64) + check<64, 64>(n_players); + else if (k == 64 and s == 48) + check<64, 48>(n_players); + else if (k == 66 and s == 64) + check<66, 64>(n_players); + else if (k == 66 and s == 48) + check<66, 48>(n_players); + else + throw runtime_error("not compiled for k=" + to_string(k) + ", s=" + to_string(s)); +} diff --git a/Check-Offline.cpp b/Check-Offline.cpp index 5ad3010c3..f2b82fb57 100644 --- a/Check-Offline.cpp +++ b/Check-Offline.cpp @@ -7,6 +7,7 @@ #include "Math/gfp.h" #include "Math/Share.h" #include "Auth/fake-stuff.h" +#include "Auth/MAC_Check.h" #include "Tools/ezOptionParser.h" #include "Exceptions/Exceptions.h" @@ -24,7 +25,7 @@ using namespace std; string PREP_DATA_PREFIX; template -void check_mult_triples(const typename T::value_type& key,int N,vector*>& dataF) +void check_mult_triples(const typename T::mac_key_type& key,int N,vector*>& dataF) { typename T::clear a,b,c,mac,res; vector Sa(N),Sb(N),Sc(N); @@ -40,7 +41,7 @@ void check_mult_triples(const typename T::value_type& key,int N,vector -void check_tuples(const typename T::value_type& key,int N,vector*>& dataF, Dtype type) +void check_tuples(const typename T::mac_key_type& key,int N,vector*>& dataF, Dtype type) { typename T::clear a,b,c,mac,res; vector Sa(N),Sb(N),Sc(N); @@ -120,7 +121,7 @@ void check_tuples(const typename T::value_type& key,int N,vector -void check_bits(const typename T::value_type& key,int N,vector*>& dataF) +void check_bits(const typename T::mac_key_type& key,int N,vector*>& dataF) { typename T::clear a,b,c,mac,res; vector Sa(N),Sb(N),Sc(N); @@ -150,7 +151,7 @@ void check_bits(const typename T::value_type& key,int N,vector } template -void check_inputs(const typename T::value_type& key,int N,vector*>& dataF) +void check_inputs(const typename T::mac_key_type& key,int N,vector*>& dataF) { typename T::clear a, mac, x; vector Sa(N); @@ -188,7 +189,7 @@ vector*> setup(int N, DataPositions& usage, int thread_num = - } template -void check(typename T::value_type key, int N, bool only_bits = false) +void check(typename T::mac_key_type key, int N, bool only_bits = false) { DataPositions usage(N); auto dataF = setup(N, usage); diff --git a/Compiler/GC/types.py b/Compiler/GC/types.py index 5be7ab228..d864426b0 100644 --- a/Compiler/GC/types.py +++ b/Compiler/GC/types.py @@ -2,7 +2,7 @@ from Compiler.types import _bitint, _number, _fix, _structure from Compiler.program import Tape, Program from Compiler.exceptions import * -from Compiler import util, oram, floatingpoint +from Compiler import util, oram, floatingpoint, library import Compiler.GC.instructions as inst import operator @@ -575,7 +575,7 @@ def Norm(self, k, f, kappa=None, simplex_flag=False): t2k = self.get_type(2 * k) acc = t2k.bit_compose(z) sign = self.bit_decompose()[-1] - signed_acc = sign.if_else(-acc, acc) + signed_acc = util.if_else(sign, -acc, acc) absolute_val_2k = t2k.bit_compose(absolute_val.bit_decompose()) part_reciprocal = absolute_val_2k * acc return part_reciprocal, signed_acc @@ -588,6 +588,17 @@ def __mul__(self, other): return other * self else: return super(sbitint, self).__mul__(other) + def cast(self, n): + bits = self.bit_decompose()[:n] + bits += [bits[-1]] * (n - len(bits)) + return self.get_type(n).bit_compose(bits) + def int_div(self, other, bit_length=None): + k = bit_length or max(self.n, other.n) + return (library.IntDiv(self.extend(k), other.extend(k), k) >> k).cast(k) + def round(self, k, m, kappa=None, nearest=None, signed=None): + bits = self.bit_decompose() + res_bits = self.bit_adder(bits[m:k], [bits[m-1]]) + return self.get_type(k - m).compose(res_bits) class sbitintvec(sbitvec): def __add__(self, other): diff --git a/Compiler/comparison.py b/Compiler/comparison.py index b972ef8ed..9dd55292c 100644 --- a/Compiler/comparison.py +++ b/Compiler/comparison.py @@ -29,6 +29,7 @@ do_precomp = True import instructions_base +import util def set_variant(options): """ Set flags based on the command-line option provided """ @@ -152,6 +153,10 @@ def TruncRoundNearest(a, k, m, kappa, signed=False): k: bit length of a m: compile-time integer """ + if k == int(program.options.ring): + # cannot work with bit length k+1 + tmp = TruncRing(None, a, k, m - 1, signed) + return TruncRing(None, tmp + 1, k - m + 1, 1, signed) from types import sint res = sint() Trunc(res, a + (1 << (m - 1)), k + 1, m, kappa, signed) @@ -165,6 +170,8 @@ def Mod2m(a_prime, a, k, m, kappa, signed): m: compile-time integer signed: True/False, describes a """ + if not util.is_constant(m): + raise CompilerError('m must be a public constant') if m >= k: movs(a_prime, a) return diff --git a/Compiler/config.py b/Compiler/config.py index 9259c74bb..f959205b9 100644 --- a/Compiler/config.py +++ b/Compiler/config.py @@ -9,13 +9,14 @@ TMP_REG = 3 TMP_REG_BASE = REG_MAX - TMP_REG -P_VALUES = { -1: 2147483713, \ - 32: 2147565569, \ +P_VALUES = { 32: 2147565569, \ 64: 9223372036855103489, \ 128: 172035116406933162231178957667602464769, \ 256: 57896044624266469032429686755131815517604980759976795324963608525438406557697, \ 512: 6703903964971298549787012499123814115273848577471136527425966013026501536706464354255445443244279389455058889493431223951165286470575994074291745908195329 } +P_VALUES[-1] = P_VALUES[128] + BIT_LENGTHS = { -1: 32, 32: 16, 64: 16, diff --git a/Compiler/floatingpoint.py b/Compiler/floatingpoint.py index 816ea9869..d3cfe89ec 100644 --- a/Compiler/floatingpoint.py +++ b/Compiler/floatingpoint.py @@ -103,6 +103,7 @@ def PreORC(a, kappa=None, m=None, raw=False): max_k = program.Program.prog.galois_length - 1 else: max_k = int(log(program.Program.prog.P) / log(2)) - kappa + assert(max_k > 0) if k <= max_k: p = [None] * m if m == k: @@ -472,25 +473,26 @@ def FLRound(x, mode): p = ((p1 + d * a) * (1 - b) + b * away_from_zero * (1 - l)) * (1 - z) return v, p, z, s -def TruncPr(a, k, m, kappa=None): +def TruncPr(a, k, m, kappa=None, signed=True): """ Probabilistic truncation [a/2^m + u] where Pr[u = 1] = (a % 2^m) / 2^m """ if isinstance(a, types.cint): return shift_two(a, m) if program.Program.prog.options.ring: - return TruncPrRing(a, k, m) + return TruncPrRing(a, k, m, signed=signed) else: return TruncPrField(a, k, m, kappa) -def TruncPrRing(a, k, m): +def TruncPrRing(a, k, m, signed=True): if m == 0: return a n_ring = int(program.Program.prog.options.ring) + assert n_ring >= k, '%d too large' % k if k == n_ring: for i in range(m): a += types.sint.get_random_bit() << i - return comparison.TruncLeakyInRing(a, k, m, True) + return comparison.TruncLeakyInRing(a, k, m, signed=signed) else: from types import sint # extra bit to mask overflow diff --git a/Compiler/library.py b/Compiler/library.py index 7e46c15c3..7853d4b65 100644 --- a/Compiler/library.py +++ b/Compiler/library.py @@ -1251,29 +1251,42 @@ def block(i): B[i] = temp return (sign_a * sign_b) * A[theta - 1] -def FPDiv(a, b, k, f, kappa, simplex_flag=False): +def IntDiv(a, b, k, kappa=None): + return FPDiv(a.extend(2 * k) << k, b.extend(2 * k) << k, 2 * k, k, + kappa, nearest=True) + +def FPDiv(a, b, k, f, kappa, simplex_flag=False, nearest=False): """ Goldschmidt method as presented in Catrina10, """ + if 2 * k == int(get_program().options.ring): + # not fitting otherwise + nearest = True + if get_program().options.binary: + # no probabilistic truncation in binary circuits + nearest = True + res_f = f + f = max((k - nearest) / 2 + 1, f) + assert 2 * f > k - nearest theta = int(ceil(log(k/3.5) / log(2))) alpha = b.get_type(2 * k).two_power(2*f) - w = AppRcr(b, k, f, kappa, simplex_flag).extend(2 * k) + w = AppRcr(b, k, f, kappa, simplex_flag, nearest).extend(2 * k) x = alpha - b.extend(2 * k) * w y = a.extend(2 *k) * w - y = y.TruncPr(2*k, f, kappa) + y = y.round(2*k, f, kappa, nearest, signed=True) for i in range(theta): x = x.extend(2 * k) y = y.extend(2 * k) * (alpha + x).extend(2 * k) x = x * x - y = y.TruncPr(2*k, 2*f, kappa) - x = x.TruncPr(2*k, 2*f, kappa) + y = y.round(2*k, 2*f, kappa, nearest, signed=True) + x = x.round(2*k, 2*f, kappa, nearest, signed=True) y = y.extend(2 * k) * (alpha + x).extend(2 * k) - y = y.TruncPr(k + 2*f, 2*f, kappa) + y = y.round(k + 2 * f, 3 * f - res_f, kappa, nearest, signed=True) return y -def AppRcr(b, k, f, kappa, simplex_flag=False): +def AppRcr(b, k, f, kappa, simplex_flag=False, nearest=False): """ Approximate reciprocal of [b]: Given [b], compute [1/b] @@ -1283,7 +1296,7 @@ def AppRcr(b, k, f, kappa, simplex_flag=False): #v should be 2**{k - m} where m is the length of the bitwise repr of [b] d = alpha - 2 * c w = d * v - w = w.TruncPr(2 * k, 2 * (k - f)) + w = w.round(2 * k, 2 * (k - f), kappa, nearest, signed=True) # now w * 2 ^ {-f} should be an initial approximation of 1/b return w diff --git a/Compiler/program.py b/Compiler/program.py index d6db92b6a..3a7fc6176 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -41,7 +41,13 @@ def __init__(self, args, options, param=-1, assemblymode=False): self.init_names(args, assemblymode) self.P = P_VALUES[param] self.param = param - self.bit_length = BIT_LENGTHS[param] + if (param != -1) + sum(x != 0 for x in(options.ring, options.field, + options.binary)) > 1: + raise CompilerError('can only use one out of -p, -B, -R, -F') + self.bit_length = int(options.ring) or int(options.binary) \ + or int(options.field) + if not self.bit_length: + self.bit_length = BIT_LENGTHS[param] print 'Default bit length:', self.bit_length self.security = 40 print 'Default security parameter:', self.security @@ -236,7 +242,6 @@ def reset_values(self): tape.reset_registers() self.mem_c = range(USER_MEM + TMP_MEM) self.mem_s = range(USER_MEM + TMP_MEM) - random.seed(0) def write_bytes(self, outfile=None): """ Write all non-empty threads and schedule to files. """ @@ -399,11 +404,10 @@ def optimize_for_gc(self): class Tape: """ A tape contains a list of basic blocks, onto which instructions are added. """ - def __init__(self, name, program, param=-1): + def __init__(self, name, program): """ Set prime p and the initial instructions and registers. """ self.program = program self.init_names(name) - self.P = P_VALUES[param] self.init_registers() self.req_tree = self.ReqNode(name) self.req_node = self.req_tree @@ -422,7 +426,6 @@ def __init__(self, name, program, param=-1): class BasicBlock(object): def __init__(self, parent, name, scope, exit_condition=None): self.parent = parent - self.P = parent.P self.instructions = [] self.name = name self.index = len(parent.basicblocks) diff --git a/Compiler/types.py b/Compiler/types.py index 2667ed5f3..2960ba394 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -290,10 +290,16 @@ def bit_compose(bits): def malloc(cls, size): return program.malloc(size, cls) + @set_instruction_type def __init__(self, reg_type, val, size): + if isinstance(val, (tuple, list)): + size = len(val) super(_register, self).__init__(reg_type, program.curr_tape, size=size) if isinstance(val, (int, long)): self.load_int(val) + elif isinstance(val, (tuple, list)): + for i, x in enumerate(val): + self.mov(self[i], type(self)(x, size=1)) elif val is not None: self.load_other(val) @@ -316,6 +322,7 @@ def expand_to_vector(self, size=None): class _clear(_register): __slots__ = [] + mov = staticmethod(movc) @vectorized_classmethod @set_instruction_type @@ -673,6 +680,7 @@ class regint(_register, _int): __slots__ = [] reg_type = 'ci' instruction_type = 'modp' + mov = staticmethod(movint) @classmethod def protect_memory(cls, start, end): @@ -890,6 +898,7 @@ def print_reg_plain(self): class _secret(_register): __slots__ = [] + mov = staticmethod(movs) PreOR = staticmethod(lambda l: floatingpoint.PreORC(l)) PreOp = staticmethod(lambda op, l: floatingpoint.PreOpL(op, l)) @@ -1288,12 +1297,13 @@ def TruncPr(self, k, m, kappa=None): return floatingpoint.TruncPr(self, k, m, kappa) @vectorize - def round(self, k, m, kappa=None, nearest=False): + def round(self, k, m, kappa=None, nearest=False, signed=False): secret = isinstance(m, sint) if nearest: if secret: raise NotImplementedError() - return comparison.TruncRoundNearest(self, k, m, kappa) + return comparison.TruncRoundNearest(self, k, m, kappa, + signed=signed) else: if secret: return floatingpoint.Trunc(self, k, m, kappa) @@ -1302,6 +1312,15 @@ def round(self, k, m, kappa=None, nearest=False): def Norm(self, k, f, kappa=None, simplex_flag=False): return library.Norm(self, k, f, kappa, simplex_flag) + @vectorize + def int_div(self, other, bit_length=None, security=None): + k = bit_length or program.bit_length + kappa = security or program.security + tmp = library.IntDiv(self, other, k, kappa) + res = type(self)() + comparison.Trunc(res, tmp, 2 * k, k, kappa, True) + return res + @staticmethod def two_power(n): return floatingpoint.two_power(n) @@ -1702,7 +1721,7 @@ def __neg__(self): return 1 + self.compose(1 ^ b for b in self.bit_decompose()) def __abs__(self): - return self.bit_decompose()[-1].if_else(-self, self) + return util.if_else(self.bit_decompose()[-1], -self, self) less_than = lambda self, other, *args, **kwargs: self < other greater_than = lambda self, other, *args, **kwargs: self > other @@ -2353,7 +2372,9 @@ def __neg__(self): def __div__(self, other): other = self.coerce(other) if isinstance(other, _fix): - return type(self)(library.FPDiv(self.v, other.v, self.k, self.f, self.kappa)) + return type(self)(library.FPDiv(self.v, other.v, self.k, self.f, + self.kappa, + nearest=self.round_nearest)) elif isinstance(other, cfix): return type(self)(library.sint_cint_division(self.v, other.v, self.k, self.f, self.kappa)) else: diff --git a/Exceptions/Exceptions.h b/Exceptions/Exceptions.h index 5bce65990..b0430f95a 100644 --- a/Exceptions/Exceptions.h +++ b/Exceptions/Exceptions.h @@ -93,6 +93,10 @@ class mac_fail: public bad_value { virtual const char* what() const throw() { return "MacCheck Failure"; } }; +class consistency_check_fail: public exception + { virtual const char* what() const throw() + { return "OT consistency check failed"; } + }; class invalid_program: public exception { virtual const char* what() const throw() { return "Invalid Program"; } diff --git a/FHEOffline/PairwiseGenerator.cpp b/FHEOffline/PairwiseGenerator.cpp index d6cc80b0a..516248a60 100644 --- a/FHEOffline/PairwiseGenerator.cpp +++ b/FHEOffline/PairwiseGenerator.cpp @@ -7,6 +7,8 @@ #include "FHEOffline/PairwiseMachine.h" #include "FHEOffline/Producer.h" +#include "Auth/MAC_Check.hpp" + template PairwiseGenerator::PairwiseGenerator(int thread_num, PairwiseMachine& machine) : diff --git a/FHEOffline/Sacrificing.cpp b/FHEOffline/Sacrificing.cpp index fcd07956f..9599db91d 100644 --- a/FHEOffline/Sacrificing.cpp +++ b/FHEOffline/Sacrificing.cpp @@ -16,7 +16,7 @@ template inline FileSacriFactory::FileSacriFactory(const char* type, const Player& P, int output_thread) { - typename T::value_type dummy; + typename T::clear dummy; /* Open file for reading in the initial triples */ stringstream file1; file1 << PREP_DIR "Initial-" << type << "-" << file_completion(dummy) diff --git a/FHEOffline/SimpleGenerator.cpp b/FHEOffline/SimpleGenerator.cpp index 670bd598f..4072cfda9 100644 --- a/FHEOffline/SimpleGenerator.cpp +++ b/FHEOffline/SimpleGenerator.cpp @@ -8,6 +8,8 @@ #include "FHEOffline/Sacrificing.h" #include "Auth/MAC_Check.h" +#include "Auth/MAC_Check.hpp" + template