diff --git a/.gitignore b/.gitignore index f2ea5d86..ca41754c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ callgrind.out.* # Compiled source # ################### +Programs/Source/* Programs/Bytecode/* Programs/Schedules/* Programs/Public-Input/* diff --git a/Auth/MAC_Check.cpp b/Auth/MAC_Check.cpp index 64d15fdc..6706985e 100644 --- a/Auth/MAC_Check.cpp +++ b/Auth/MAC_Check.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Auth/MAC_Check.h" @@ -366,16 +366,76 @@ void Direct_MAC_Check::POpen_End(vector& values,const vector >& S this->CheckIfNeeded(P); } +template +Passing_MAC_Check::Passing_MAC_Check(const T& ai, Names& Nms, int num) : + Separate_MAC_Check(ai, Nms, num) +{ +} + +template +void passing_add_openings(vector& values, octetStream& os) +{ + octetStream new_os; + for (unsigned int i=0; i +void Passing_MAC_Check::POpen_Begin(vector& values,const vector >& S,const Player& P) +{ + values.resize(S.size()); + this->os.reset_write_head(); + for (unsigned int i=0; ios); + values[i] = S[i].get_share(); + } + this->AddToMacs(S); + + for (int i = 0; i < P.num_players() - 1; i++) + { + P.pass_around(this->os); + if (T::t() == 2) + passing_add_openings(values, this->os); + else + passing_add_openings(values, this->os); + } + + for (unsigned int i = 0; i < values.size(); i++) + { + T tmp; + tmp.unpack(this->os); + this->vals.push_back(tmp); + } +} + +template +void Passing_MAC_Check::POpen_End(vector& values,const vector >& S,const Player& P) +{ + (void)S; + this->GetValues(values); + 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 diff --git a/Auth/MAC_Check.h b/Auth/MAC_Check.h index 2bc3e5bc..d15ab55a 100644 --- a/Auth/MAC_Check.h +++ b/Auth/MAC_Check.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _MAC_Check #define _MAC_Check @@ -161,6 +161,16 @@ public: 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 }; diff --git a/Auth/Subroutines.cpp b/Auth/Subroutines.cpp index 8c820a87..b5d1b74a 100644 --- a/Auth/Subroutines.cpp +++ b/Auth/Subroutines.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Auth/Subroutines.h" diff --git a/Auth/Subroutines.h b/Auth/Subroutines.h index 50daee6f..316a94d6 100644 --- a/Auth/Subroutines.h +++ b/Auth/Subroutines.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Subroutines #define _Subroutines diff --git a/Auth/Summer.cpp b/Auth/Summer.cpp index 5aa29b43..c81b7dbf 100644 --- a/Auth/Summer.cpp +++ b/Auth/Summer.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Summer.cpp diff --git a/Auth/Summer.h b/Auth/Summer.h index 78df33d8..00fc44d6 100644 --- a/Auth/Summer.h +++ b/Auth/Summer.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Summer.h diff --git a/Auth/fake-stuff.cpp b/Auth/fake-stuff.cpp index bec345a2..8d581752 100644 --- a/Auth/fake-stuff.cpp +++ b/Auth/fake-stuff.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/gf2n.h" diff --git a/Auth/fake-stuff.h b/Auth/fake-stuff.h index d4f4c144..e7346434 100644 --- a/Auth/fake-stuff.h +++ b/Auth/fake-stuff.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _fake_stuff diff --git a/BMR/AndJob.cpp b/BMR/AndJob.cpp new file mode 100644 index 00000000..6183ddd9 --- /dev/null +++ b/BMR/AndJob.cpp @@ -0,0 +1,38 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * AndJob.cpp + * + */ + +#include "AndJob.h" +#include "Party.h" +#include "Register_inline.h" + +int AndJob::run() +{ +#ifdef DEBUG_AND_JOB + printf("thread %d: run and job from %d to %d with %d gates\n", + pthread_self(), start, end, gates.size()); +#endif + __m128i prf_output[PAD_TO_8(MAX_N_PARTIES)]; + auto gate = gates.begin(); + vector< GC::Secret >& S = *this->S; + const vector& args = *this->args; + int i_gate = 0; + for (size_t i = start; i < end; i += 4) + { + GC::Secret& dest = S[args[i + 1]]; + for (int j = 0; j < args[i]; j++) + { + i_gate++; + gate->init_inputs(gate_id + i_gate, + ProgramParty::s().get_n_parties()); + dest.get_reg(j).eval(S[args[i + 2]].get_reg(j), + S[args[i + 3]].get_reg(0), *gate, + ProgramParty::s().get_id(), (char*) prf_output, 0, 0, 0); + gate++; + } + } + return i_gate; +} diff --git a/BMR/AndJob.h b/BMR/AndJob.h new file mode 100644 index 00000000..6679cffa --- /dev/null +++ b/BMR/AndJob.h @@ -0,0 +1,44 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * AndJob.h + * + */ + +#ifndef BMR_ANDJOB_H_ +#define BMR_ANDJOB_H_ + +#include "GC/Secret.h" +#include "Register.h" + +#include +using namespace std; + +class AndJob +{ + vector< GC::Secret >* S; + const vector* args; + +public: + vector gates; + size_t start, end; + gate_id_t gate_id; + + AndJob() : S(0), args(0), start(0), end(0), gate_id(0) {} + + void reset(vector >& S, const vector& args, + size_t start, gate_id_t gate_id, size_t n_gates, int n_parties) + { + this->S = &S; + this->args = &args; + this->start = start; + this->end = start; + this->gate_id = gate_id; + if (gates.size() < n_gates) + gates.resize(n_gates, {n_parties}); + } + + int run(); +}; + +#endif /* BMR_ANDJOB_H_ */ diff --git a/BMR/BooleanCircuit.cpp b/BMR/BooleanCircuit.cpp index 14c46b61..7387a56e 100644 --- a/BMR/BooleanCircuit.cpp +++ b/BMR/BooleanCircuit.cpp @@ -1,14 +1,16 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #include "BooleanCircuit.h" #include "prf.h" -static void throw_party_exists(pid_t pid, unsigned int pos) { - std::cout << "ERROR: in circuit description" << std::endl - << "\tPosition: " << pos << std::endl - << "\tPlayer id " << pid << " already exists" << std::endl; - throw std::invalid_argument( "player id error" ); -} +//static void throw_party_exists(pid_t pid, unsigned int pos) { +// std::cout << "ERROR: in circuit description" << std::endl +// << "\tPosition: " << pos << std::endl +// << "\tPlayer id " << pid << " already exists" << std::endl; +// throw std::invalid_argument( "player id error" ); +//} static void throw_bad_circuit_file() { std::cout << "ERROR: could not read circuit file" << std::endl; @@ -27,7 +29,7 @@ void BooleanCircuit::_parse_circuit(const char* desc_file) unsigned int total_input_wires; circuit_file >> total_input_wires; - for (int idx_party = 1; idx_party <= _num_parties; idx_party++) { + for (size_t idx_party = 1; idx_party <= _num_parties; idx_party++) { unsigned int num_input_wires = total_input_wires/_num_parties; if (idx_party == _num_parties) { num_input_wires = total_input_wires-(total_input_wires/_num_parties)*(_num_parties-1); @@ -53,7 +55,7 @@ void BooleanCircuit::_parse_circuit(const char* desc_file) /* Parse gates */ for (gate_id_t gate_id = 1; gate_id <= _num_gates; gate_id++) { - int fan_in, fan_out, left, right, out; + size_t fan_in, fan_out, left, right, out; std::string func; circuit_file >> fan_in >> fan_out >> left >> right >> out >> func; @@ -163,11 +165,11 @@ int BooleanCircuit::__make_layers(gate_id_t g) return 0; } int layer_left, layer_right; - if(_gates[g]._left == NULL) + if(_gates[g]._left == 0) layer_left = -1; else layer_left = __make_layers(_wires[_gates[g]._left]._out_from); - if(_gates[g]._right == NULL) + if(_gates[g]._right == 0) layer_right = -1; else layer_right = __make_layers(_wires[_gates[g]._right]._out_from); @@ -183,7 +185,7 @@ int BooleanCircuit::__make_layers(gate_id_t g) void BooleanCircuit::_add_to_layer(int layer, gate_id_t g) { // printf("adding %u to layer %d\n", g, layer); - if (_layers.size() _max_layer_sz) { _max_layer_sz = _layers[i].size(); @@ -245,7 +247,7 @@ void BooleanCircuit::Inputs(const char* inputs_file_path) } BooleanCircuit::BooleanCircuit(const char* desc_file) -:_num_evaluated_out_wires(0),_num_input_wires(0), _keys(NULL), _masks(NULL), _prf_inputs(NULL) +:_num_evaluated_out_wires(0) { _parse_circuit(desc_file); _make_layers(); @@ -259,18 +261,17 @@ void BooleanCircuit::EvaluateByLayerLinearly(party_id_t my_id) { mpz_t temp_mpz; init_temp_mpz_t(temp_mpz); #endif - for(int i=0; i<_layers.size(); i++) { - for (int j=0; j<_layers[i].size(); j++) { + for(size_t i=0; i<_layers.size(); i++) { + for (size_t j=0; j<_layers[i].size(); j++) { gate_id_t gid = _layers[i][j]; #ifdef __PURE_SHE__ - signal_t s = _eval_gate(gid, my_id, prf_output, temp_mpz); + _eval_gate(gid, my_id, prf_output, temp_mpz); #else - signal_t s = _eval_gate(gid, my_id, prf_output); + _eval_gate(gid, my_id, prf_output); #endif -// printf("%d ", s); - _externals[_gates[gid]._out] = s; } } + delete[] prf_output; } void BooleanCircuit::EvaluateByLayer(int num_threads, party_id_t my_id) @@ -291,7 +292,7 @@ void BooleanCircuit::_eval_by_layer(int i, int num_threads, party_id_t my_id) mpz_t temp_mpz; init_temp_mpz_t(temp_mpz); #endif - for(int l=0; l<_layers.size(); l++) { + for(size_t l=0; l<_layers.size(); l++) { int layer_sz = _layers[l].size(); int start_idx = (layer_sz/num_threads)*i; int end_idx = (layer_sz/num_threads)*(i+1)-1; @@ -301,11 +302,10 @@ void BooleanCircuit::_eval_by_layer(int i, int num_threads, party_id_t my_id) for(int g=start_idx; g<=end_idx; g++) { gate_id_t gid = _layers[l][g]; #ifdef __PURE_SHE__ - signal_t s = _eval_gate(gid, my_id, prf_output, temp_mpz); + _eval_gate(gid, my_id, prf_output, temp_mpz); #else - signal_t s = _eval_gate(gid, my_id, prf_output); + _eval_gate(gid, my_id, prf_output); #endif - _externals[_gates[gid]._out] = s; } // printf("done eval layer %d\n", l); @@ -375,75 +375,17 @@ void BooleanCircuit::_eval_by_layer(int i, int num_threads, party_id_t my_id) //} #ifdef __PURE_SHE__ -signal_t BooleanCircuit::_eval_gate(gate_id_t g, party_id_t my_id, char* prf_output, mpz_t& tmp_mpz) +void BooleanCircuit::_eval_gate(gate_id_t g, party_id_t my_id, char* prf_output, mpz_t& tmp_mpz) #else -signal_t BooleanCircuit::_eval_gate(gate_id_t g, party_id_t my_id, char* prf_output) +void BooleanCircuit::_eval_gate(gate_id_t g, party_id_t my_id, char* prf_output) #endif { // std::cout << std::endl << "evaluate gate " << g << std::endl; wire_id_t w_l = _gates[g]._left; wire_id_t w_r = _gates[g]._right; wire_id_t w_o = _gates[g]._out; - int sig_l = _externals[w_l]; - int sig_r = _externals[w_r]; - int entry = 2 * sig_l + sig_r; - - Key* garbled_entry = _garbled_entry(g, entry); - int ext_l = entry%2 ? 1 : 0 ; - int ext_r = entry<2 ? 0 : 1 ; - - Key k; - for(party_id_t i=1; i<=_num_parties; i++) { -// std::cout << "using key: " << *_key(i,w_l,sig_l) << ": "; - PRF_chunk(_key(i,w_l,sig_l), _input(ext_l,g,1), prf_output, PAD_TO_8(_num_parties)); - for(party_id_t j=1; j<=_num_parties; j++) { - k = *(Key*)(prf_output+16*(j-1)); -#ifdef __PRIME_FIELD__ - k.adjust(); -#endif -// printf("Fk^%d_{%u,%d}(%d,%u,%d) = ",i, w_l, sig_l,ext_l,g,j); -// std::cout << k << std::endl; - garbled_entry[j-1] -= k; - } - - PRF_chunk(_key(i,w_r,sig_r), _input(ext_r,g,1) , prf_output, PAD_TO_8(_num_parties)); - for(party_id_t j=1; j<=_num_parties; j++) { -// std::cout << "using key: " << *_key(i,w_r,sig_r) << ": "; - k = *(Key*)(prf_output+16*(j-1)); -#ifdef __PRIME_FIELD__ - k.adjust(); -#endif -// printf("Fk^%d_{%u,%d}(%d,%u,%d) = ",i, w_r, sig_r,ext_r,g,j); -// std::cout << k << std::endl; - garbled_entry[j-1] -= k; - } - } - -#if __PURE_SHE__ - for(party_id_t j=1; j<=_num_parties; j++) { - garbled_entry[j-1].sqr_in_place(tmp_mpz); - } -#endif - -// for(party_id_t i=1; i<=_num_parties; i++) { -// std::cout << garbled_entry[i-1] << " "; -// } -// std::cout << std::endl; - - if(garbled_entry[my_id-1] == *_key(my_id, w_o, 0)) { -// std::cout << "k^"<registers[w_o].eval(party->registers[w_l], party->registers[w_r], + party->_garbled_tbl[g-1], my_id, prf_output, w_o, w_l, w_r); } @@ -522,12 +464,11 @@ std::string BooleanCircuit::Output() { std::cout << "output:" <registers[_output_start+i].mask << endl; + cout << "external " << i << ": " << (int)party->registers[_output_start+i].get_external() << endl; + int output = party->registers[_output_start+i].get_output(); ss << output; } std::cout << ss.str(); diff --git a/BMR/BooleanCircuit.h b/BMR/BooleanCircuit.h index 61acd4ef..f6f2a502 100644 --- a/BMR/BooleanCircuit.h +++ b/BMR/BooleanCircuit.h @@ -1,3 +1,5 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #ifndef __BOOLEAN_CIRCUIT__ #define __BOOLEAN_CIRCUIT__ @@ -22,10 +24,10 @@ #include "Gate.h" #include "Wire.h" #include "Key.h" +#include "Register.h" +#include "GarbledGate.h" -typedef unsigned int party_id_t; - -//#include "Party.h" +#include "Party.h" #define INIT_PARTY(W,N) {.wires=W, .n_wires=N } @@ -41,13 +43,11 @@ typedef struct party_t{ #define GARBLED_GATE_SIZE(N) (4*N) #define MSG_KEYS_HEADER_SZ (16) -//#define PAD_TO_8(n) (n+8-n%8) -#define PAD_TO_8(n) (n) - class BooleanCircuit { friend class Party; friend class TrustedParty; + friend class CommonCircuitParty; public: BooleanCircuit(const char* desc_file); // void RawInputs(std::string raw_inputs); @@ -63,15 +63,7 @@ public: inline wire_id_t OutWiresStart() { return _output_start; } inline gate_id_t NumGates() {return _num_gates; } inline wire_id_t NumParties() { return _num_parties; } - inline party_t Party(party_id_t id) {return _parties[id];} - inline void Keys(Key* keys) {_keys = keys;} - inline Key* Keys() { return _keys; } - inline void Masks(char* masks) {_masks = masks;} - inline char* Masks() { return _masks; } - inline char* PrfInputs() {return _prf_inputs;} - inline void PrfInputs(char* prf_inputs) { _prf_inputs = prf_inputs; } - inline char* Prfs(){return _prfs;} - inline void Prfs(char* prfs){_prfs=prfs;} + inline party_t get_party(party_id_t id) {return _parties[id];} private: @@ -88,7 +80,7 @@ private: std::vector> _layers; - int _max_layer_sz; + size_t _max_layer_sz; void _make_layers(); int __make_layers(gate_id_t g); void _add_to_layer(int layer, gate_id_t g); @@ -111,13 +103,13 @@ private: void _parse_circuit(const char* desc_file); void _eval_thread(party_id_t my_id); #ifdef __PURE_SHE__ - signal_t _eval_gate(gate_id_t g, party_id_t my_id, char* prf_output, mpz_t& tmp_mpz); + void _eval_gate(gate_id_t g, party_id_t my_id, char* prf_output, mpz_t& tmp_mpz); #else - signal_t _eval_gate(gate_id_t g, party_id_t my_id, char* prf_output); + void _eval_gate(gate_id_t g, party_id_t my_id, char* prf_output); #endif inline bool is_wire_ready(wire_id_t w) { - return _externals[w] != NO_SIGNAL; + return party->registers[w].get_external() != NO_SIGNAL; } inline bool is_gate_ready(gate_id_t g) { bool ready = is_wire_ready(_gates[g]._left) @@ -125,73 +117,7 @@ private: return ready; } - /* Additional data stored per per party per wire: */ - Key* _keys; /* Total of n*W*2 keys - * For every w={0,...,W} - * For every b={0,1} - * For every i={1...n} - * k^i_{w,b} - * This is helpful that the keys for specific w and b are adjacent - * for pipelining matters. - */ - inline Key* _key(party_id_t i, wire_id_t w,int b) {return _keys+ w*2*_num_parties + b*_num_parties + i-1 ; } - -#ifdef __PURE_SHE__ - Key* _sqr_keys; - inline Key* _sqr_key(party_id_t i, wire_id_t w,int b) {return _sqr_keys+ w*2*_num_parties + b*_num_parties + i-1 ; } -#endif - - char* _masks; /* There are W masks, one per wire. beginning with 0 */ - char* _externals; /* Same as _masks */ - - Key* _garbled_tbl; /* will be allocated 4*n*G keys; - * (n keys for each of A,B,C,D entries). - * For each g in G: - * A1, A2, ... , An - * B1, B2, ... , Bn - * C1, C2, ... , Cn - * D1, D2, ... , Dn - */ - Key* _garbled_tbl_copy; - inline Key* _garbled_entry(gate_id_t g, int entry) {return _garbled_tbl+(g-1)*4*_num_parties+entry*_num_parties;} - - char* _prfs; /* - * Total of n*(G*2*2*2*n+4) = n*(8*G*n+RESERVE_FOR_MSG_TYPE) = n*(PRFS_PER_PARTY+RESERVE_FOR_MSG_TYPE) - * - * For every party i={1...n} - * = saves us copying memory to another location - only for Party. - * For every gate g={1...G} - * For input wires x={left,right} - * For b={0,1} (0-key/1-key) - * For e={0,1} (extension) - * for every party j={1...n} - * F_{k^i_{x,b}}(e,j,g,) - */ - - - char* _prf_inputs; /* - * These are all possible inputs to the prf, - * This is not efficient in terms of storage but increase - * performance in terms of speed since no need to generate - * (new allocation plus filling) those inputs every time - * we compute the prf. - * Structure: - * - Total of G*n*2 inputs. (i.e. for every gate g, for every - * party j and for every extension e (from {0,1}). - * - We want to be able to set key once and use it to encrypt - * several inputs, so we want those inputs to be adjacent in - * memory in order to save time of building the block of - * inputs. So, the structure of the inputs is as follows: - * - First half of inputs (G*n inputs) are: - * - For every gate g=1,...,G we store the inputs: - * (0||g||1),(0||g||2),...,(0||g||n) - * - Second half of the inputs are: - * - For every gate g=1,...,G we store the inputs: - * (1||g||1),(1||g||2),...,(1||g||n) - */ - inline char* _input(int e, gate_id_t g, party_id_t j) - { return _prf_inputs + (e*_num_gates*_num_parties + (g-1)*_num_parties + j-1) * 16 ;} - + Party* party; }; diff --git a/BMR/CommonParty.cpp b/BMR/CommonParty.cpp new file mode 100644 index 00000000..239090e7 --- /dev/null +++ b/BMR/CommonParty.cpp @@ -0,0 +1,219 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * CommonParty.cpp + * + */ + +#include "CommonParty.h" +#include "BooleanCircuit.h" +#include "Tools/benchmarking.h" + +CommonParty* CommonParty::singleton = 0; + +CommonParty::CommonParty() : + _node(0), gate_counter(0), gate_counter2(0), garbled_tbl_size(0), + cpu_timer(CLOCK_PROCESS_CPUTIME_ID), buffers(TYPE_MAX) +{ + insecure("MPC emulation"); + if (singleton != 0) + throw runtime_error("there can only be one"); + singleton = this; + prng.ReSeed(); +#ifdef DEBUG_PRNG + octet seed[SEED_SIZE]; + memset(seed, 0, sizeof(seed)); + prng.SetSeed(seed); +#endif + cpu_timer.start(); + timer.start(); + gf2n::init_field(128); + mac_key.randomize(prng); +} + +CommonParty::~CommonParty() +{ + if (_node) + delete _node; + cout << "Wire storage: " << 1e-9 * wires.capacity() << " GB" << endl; + cout << "CPU time: " << cpu_timer.elapsed() << endl; + cout << "Total time: " << timer.elapsed() << endl; + cout << "First phase time: " << timers[0].elapsed() << endl; + cout << "Second phase time: " << timers[1].elapsed() << endl; + cout << "Number of gates: " << gate_counter << endl; +} + +void CommonParty::init(const char* netmap_file, int id, int n_parties) +{ +#ifdef N_PARTIES + if (n_parties != N_PARTIES) + throw runtime_error("wrong number of parties"); +#else +#ifdef MAX_N_PARTIES + if (n_parties > MAX_N_PARTIES) + throw runtime_error("too many parties"); +#endif + _N = n_parties; +#endif // N_PARTIES + printf("netmap_file: %s\n", netmap_file); + if (0 == strcmp(netmap_file, LOOPBACK_STR)) { + _node = new Node( NULL, id, this, _N + 1); + } else { + _node = new Node(netmap_file, id, this); + } +} + +int CommonParty::init(const char* netmap_file, int id) +{ + int n_parties; + if (string(netmap_file) != string(LOOPBACK_STR)) + { + ifstream(netmap_file) >> n_parties; + n_parties--; + } + else + n_parties = 2; + init(netmap_file, id, n_parties); + return n_parties; +} + +void CommonParty::reset() +{ + garbled_tbl_size = 0; +} + +gate_id_t CommonParty::new_gate() +{ + gate_counter++; + garbled_tbl_size++; + return gate_counter; +} + +void CommonParty::next_gate(GarbledGate& gate) +{ + gate_counter2++; + gate.init_inputs(gate_counter2, _N); +} + +void CommonParty::input(Register& reg, party_id_t from) +{ + (void)reg; + (void)from; + throw not_implemented(); +} + +SendBuffer& CommonParty::get_buffer(MSG_TYPE type) +{ + SendBuffer& buffer = buffers[type]; + buffer.clear(); + fill_message_type(buffer, type); +#ifdef DEBUG_BUFFER + cout << type << " buffer:"; + phex(buffers.data(), 4); +#endif + return buffer; +} + +void CommonCircuitParty::print_masks(const vector& indices) +{ + vector bits; + for (auto i = indices.begin(); i != indices.end(); i++) + bits.push_back(registers[*i].get_mask_no_check()); + print_bit_array(bits); +} + +void CommonCircuitParty::print_outputs(const vector& indices) +{ + vector bits; + for (auto i = indices.begin(); i != indices.end(); i++) + bits.push_back(registers[*i].get_output_no_check()); + print_bit_array(bits); +} + + +template +GC::BreakType CommonParty::first_phase(GC::Program& program, + GC::Processor& processor, GC::Machine& machine) +{ + (void)machine; + timers[0].start(); + reset(); + wires.clear(); + GC::BreakType next = (reinterpret_cast*>(&program))->execute(processor); +#ifdef DEBUG_ROUNDS + cout << "finished first phase at pc " << processor.PC + << " reason " << next << endl; +#endif + timers[0].stop(); + cout << "First round time: " << timers[0].elapsed() << " / " + << timer.elapsed() << endl; +#ifdef DEBUG_WIRES + cout << "Storing wires with " << 1e-9 * wires.size() << " GB on disk" << endl; +#endif + wire_storage.push(wires); + return next; +} + +template +GC::BreakType CommonParty::second_phase(GC::Program& program, + GC::Processor& processor, GC::Machine& machine) +{ + (void)machine; + wire_storage.pop(wires); + wires.reset_head(); + timers[1].start(); + GC::BreakType next = GC::TIME_BREAK; + next = program.execute(processor); +#ifdef DEBUG_ROUNDS + cout << "finished second phase at " << processor.PC + << " reason " << next << endl; +#endif + timers[1].stop(); +// cout << "Second round time: " << timers[1].elapsed() << ", "; +// cout << "total time: " << timer.elapsed() << endl; + if (false) + return GC::CAP_BREAK; + else + return next; +} + +void CommonCircuitParty::prepare_input_regs(party_id_t from) +{ + party_t sender = _circuit->_parties[from]; + wire_id_t s = sender.wires; //the beginning of my wires + wire_id_t n = sender.n_wires; // number of my wires + input_regs_queue.clear(); + input_regs_queue.push_back(_N + 1); + (*input_regs)[from].clear(); + for (wire_id_t i = 0; i < n; i++) { + wire_id_t w = s + i; + (*input_regs)[from].push_back(w); + } +} + +void CommonCircuitParty::prepare_output_regs() +{ + output_regs.clear(); + for (size_t i = 0; i < _OW; i++) + output_regs.push_back(_circuit->OutWiresStart()+i); +} + +template GC::BreakType CommonParty::first_phase( + GC::Program >& program, + GC::Processor >& processor, + GC::Machine >& machine); + +template GC::BreakType CommonParty::first_phase( + GC::Program >& program, + GC::Processor >& processor, + GC::Machine >& machine); + +template GC::BreakType CommonParty::second_phase( + GC::Program >& program, + GC::Processor >& processor, + GC::Machine >& machine); + +template GC::BreakType CommonParty::second_phase( + GC::Program >& program, + GC::Processor >& processor, + GC::Machine >& machine); diff --git a/BMR/CommonParty.h b/BMR/CommonParty.h new file mode 100644 index 00000000..3adfdef3 --- /dev/null +++ b/BMR/CommonParty.h @@ -0,0 +1,163 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * CommonParty.h + * + */ + +#ifndef BMR_COMMONPARTY_H_ +#define BMR_COMMONPARTY_H_ + +#include +using namespace std; + +#include "GarbledGate.h" +#include "Register.h" +#include "proto_utils.h" +#include "network/Node.h" +#include "Tools/random.h" +#include "Auth/MAC_Check.h" +#include "Tools/time-func.h" +#include "GC/Program.h" +#include "Tools/FlexBuffer.h" + +#if (defined(DEBUG) || defined(DEBUG_COMM)) && !defined(DEBUG_STEPS) +#define DEBUG_STEPS +#endif + +enum SpdzOp +{ + SPDZ_LOAD, + SPDZ_STORE, + SPDZ_MAC, + SPDZ_OP_N, +}; + +template +class PersistentFront +{ + deque& container; + int i; +public: + PersistentFront(deque& container) : container(container), i(0) {} + T& operator*() { return container.front(); } + void operator++(int) { i++; } + void reset() {} + int get_i() { return i; } +}; + +class CommonParty : public NodeUpdatable +{ +protected: + friend class Register; + +#ifdef N_PARTIES + const party_id_t _N = N_PARTIES; +#else + party_id_t _N; +#endif + Node* _node; + + int gate_counter, gate_counter2; + int garbled_tbl_size; + + Timer cpu_timer; + Timer timers[2]; + Timer timer; + + gf2n mac_key; + + mutex global_lock; + + LocalBuffer wires; + ReceivedMsgStore wire_storage; + + template + GC::BreakType first_phase(GC::Program& program, GC::Processor& processor, + GC::Machine& machine); + template + GC::BreakType second_phase(GC::Program& program, GC::Processor& processor, + GC::Machine& machine); + +public: + static CommonParty* singleton; + static CommonParty& s(); + + vector buffers; + + PRNG prng; + + CommonParty(); + virtual ~CommonParty(); + +#ifdef N_PARTIES + static int get_n_parties() { return N_PARTIES; } +#else + static int get_n_parties() { return s()._N; } +#endif + + void init(const char* netmap_file, int id, int n_parties); + int init(const char* netmap_file, int id); + virtual void reset(); + + gate_id_t new_gate(); + void next_gate(GarbledGate& gate); + gate_id_t next_gate(int skip) { return gate_counter2 += skip; } + size_t get_garbled_tbl_size() { return garbled_tbl_size; } + + void input(Register& reg, party_id_t from); + + SendBuffer& get_buffer(MSG_TYPE type); + + gf2n get_mac_key() { return mac_key; } +}; + +class BooleanCircuit; + +class CommonCircuitParty : virtual public CommonParty +{ +protected: + BooleanCircuit* _circuit; + gate_id_t _G; + wire_id_t _W; + wire_id_t _OW; + + CheckVector registers; + + deque< CheckVector< CheckVector > > input_regs_queue; + PersistentFront< CheckVector< CheckVector > > input_regs; + vector output_regs; + + CommonCircuitParty() : input_regs(input_regs_queue) {} + + void prepare_input_regs(party_id_t id); + void prepare_output_regs(); + + void resize_registers() { registers.resize(_W, {(int)_N}); } + + Register& get_reg(int reg); + + void print_masks(const vector& indices); + void print_outputs(const vector& indices); + void print_round_regs(); +}; + + +inline Register& CommonCircuitParty::get_reg(int reg) +{ +#ifdef DEBUG_REGS + cout << "get reg " << reg << endl << registers.at(reg).keys[0] << endl + << registers.at(reg).keys[1] << endl; +#endif + return registers.at(reg); +} + +inline CommonParty& CommonParty::s() +{ + if (singleton) + return *singleton; + else + throw runtime_error("no singleton"); +} + +#endif /* BMR_COMMONPARTY_H_ */ diff --git a/BMR/GarbledGate.cpp b/BMR/GarbledGate.cpp new file mode 100644 index 00000000..4d9136d5 --- /dev/null +++ b/BMR/GarbledGate.cpp @@ -0,0 +1,97 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * GarbledGate.cpp + * + */ + +#include "GarbledGate.h" +#include "prf.h" +#include "CommonParty.h" + +GarbledGate::~GarbledGate() { +} + +void GarbledGate::init_inputs(gate_id_t g, int n_parties) +{ + n_parties = CommonParty::get_n_parties(); + id = g; + for (unsigned int e = 0; e <= 1; e++) { + prf_inputs[e].resize(n_parties); + for (unsigned int j = 0; j < (size_t)n_parties; j++) { + prf_inputs[e][j] = 0; + + /* fill out this buffer s.t. first 4 bytes are the extension (0/1), + * next 4 bytes are gate_id and next 4 bytes are party id. + * For the first half we dont need to fill the extension because + * it is zero anyway. + */ + + unsigned int* prf_input_index = + (unsigned int*) &prf_inputs[e][j]; //easier to refer as integers + // printf("e,g,j=%u,%u,%u\n",e,g,j); + *prf_input_index = e; + *(prf_input_index + 1) = g; + *(prf_input_index + 2) = j + 1; + } + } +} + +void GarbledGate::compute_prfs_outputs(const Register** in_wires, int my_id, + SendBuffer& buffer, gate_id_t g) +{ + int n_parties = CommonParty::get_n_parties(); + init_inputs(g, n_parties); + PRFOutputs prf_output(n_parties); + for(int w=0; w<=1; w++) { + for (int b=0; b<=1; b++) { + const Key& key = in_wires[w]->key(my_id, b); + AES_KEY aes_key; + AES_128_Key_Expansion((unsigned char*)&key.r, &aes_key); +#ifdef DEBUG + cout << "using key " << key << endl; +#endif + for (int e=0; e<=1; e++) { + for (int j=1; j<= n_parties; j++) { + prf_output[my_id-1][j-1].outputs[w][b][e][0] = + aes_128_encrypt(*(__m128i*)input(e, j), (octet*)aes_key.rd_key); +#ifdef __PRIME_FIELD__ + ((Key*)prf_outputs_index)->adjust(); +#endif + } + } + } + } + for (int i = 0; i < n_parties; i++) + buffer.serialize(prf_output[my_id - 1][i]); +#ifdef DEBUG + wire_id_t wire_ids[] = { (wire_id_t)in_wires[0]->get_id(), (wire_id_t)in_wires[1]->get_id() }; + prf_output.print_prfs(g, wire_ids, my_id, n_parties); +#endif +} + +void PRFOutputs::print_prfs(gate_id_t g, wire_id_t* in_wires, party_id_t my_id, int n_parties) +{ + for(int w=0; w<=1; w++) { + for (int b=0; b<=1; b++) { + for (int e=0; e<=1; e++) { + for(party_id_t j=1; j<=(size_t)n_parties; j++) { + printf("F_k^%d_{%lu,%u}(%d,%lu,%u) = ", my_id, in_wires[w], b, e, g, j); + Key k = *((Key*)(*this)[my_id-1][j-1].outputs[w][b][e]); + std::cout << k << std::endl; + } + } + } + } +} + +void GarbledGate::print() +{ + cout << "garbled gate " << id << endl; + for (int i = 0; i < 4; i++) + { + for (size_t j = 0; j < keys[i].size(); j++) + cout << keys[i][j] << " "; + cout << endl; + } +} diff --git a/BMR/GarbledGate.h b/BMR/GarbledGate.h new file mode 100644 index 00000000..e3fd5cd0 --- /dev/null +++ b/BMR/GarbledGate.h @@ -0,0 +1,90 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * GarbledGate.h + * + */ + +#ifndef BMR_PRIME_CIRCUIT_BMR_INC_GARBLEDGATE_H_ +#define BMR_PRIME_CIRCUIT_BMR_INC_GARBLEDGATE_H_ + +#include "Register.h" +#include "common.h" + +struct PRFTuple { + Key outputs[2][2][2][1]; +}; + +/* + * Total of n*(G*2*2*2*n+4) = n*(8*G*n+RESERVE_FOR_MSG_TYPE) = n*(PRFS_PER_PARTY+RESERVE_FOR_MSG_TYPE) + * + * For every party i={1...n} + * = saves us copying memory to another location - only for Party. + * For every gate g={1...G} + * For input wires x={left,right} + * For b={0,1} (0-key/1-key) + * For e={0,1} (extension) + * for every party j={1...n} + * F_{k^i_{x,b}}(e,j,g,) + */ +struct PRFOutputs { +#ifdef MAX_N_PARTIES + PRFTuple tuples[MAX_N_PARTIES][MAX_N_PARTIES]; + PRFOutputs(int n_parties) { (void)n_parties; } + PRFTuple* operator[](int i) { return tuples[i]; } +#else + vector tuples; + int n_parties; + + PRFOutputs(int n_parties) : n_parties(n_parties), tuples(n_parties * n_parties) {} + PRFTuple* operator[](int i) { return &tuples[i*n_parties]; } +#endif + void print_prfs(gate_id_t g, wire_id_t* in_wires, party_id_t my_id, int n_parties); +}; + +class GarbledGate : public KeyTuple<4> { + /* will be allocated 4*n keys; + * (n keys for each of A,B,C,D entries): + * A1, A2, ... , An + * B1, B2, ... , Bn + * C1, C2, ... , Cn + * D1, D2, ... , Dn + */ + +public: + KeyVector prf_inputs[2]; /* + * These are all possible inputs to the prf, + * This is not efficient in terms of storage but increase + * performance in terms of speed since no need to generate + * (new allocation plus filling) those inputs every time + * we compute the prf. + * Structure: + * - Total of G*n*2 inputs. (i.e. for every gate g, for every + * party j and for every extension e (from {0,1}). + * - We want to be able to set key once and use it to encrypt + * several inputs, so we want those inputs to be adjacent in + * memory in order to save time of building the block of + * inputs. So, the structure of the inputs is as follows: + * - First half of inputs (G*n inputs) are: + * - For every gate g=1,...,G we store the inputs: + * (0||g||1),(0||g||2),...,(0||../circuit_bmr/inc/GarbledGate.h:43:19: error: ‘gate_id_t’ has not been declared + * g||n) + * - Second half of the inputs are: + * - For every gate g=1,...,G we store the inputs: + * (1||g||1),(1||g||2),...,(1||g||n) + */ + + gate_id_t id; + + GarbledGate(int n_parties) : KeyTuple<4>(n_parties), id(-1) {} + virtual ~GarbledGate(); + + void init_inputs(gate_id_t g, int n_parties); + + char* input(int e, party_id_t j) { return (char*)&prf_inputs[e][j-1]; } + + void compute_prfs_outputs(const Register** in_wires, int my_id, SendBuffer& buffer, gate_id_t g); + void print(); +}; + +#endif /* BMR_PRIME_CIRCUIT_BMR_INC_GARBLEDGATE_H_ */ diff --git a/BMR/Gate.h b/BMR/Gate.h index d0dc378a..e1c7f4c1 100644 --- a/BMR/Gate.h +++ b/BMR/Gate.h @@ -1,32 +1,33 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #ifndef __GATE_H__ #define __GATE_H__ #include #include -#include #include #include "Key.h" #define NO_LAYER (-1) -typedef struct Gate { +class Gate { +public: wire_id_t _left; wire_id_t _right; wire_id_t _out; - uint8_t _func[4]; + Function _func; int _layer; + Gate() : _left(-1), _right(-1), _out(-1), _layer(-1) {} + inline void init(wire_id_t left, wire_id_t right, wire_id_t out,std::string func) { _left = left; _right = right; _out = out; - _func[0] = (func[0]=='0')?0:1;//TODO change to func[0]-0x30 - _func[1] = (func[1]=='0')?0:1; - _func[2] = (func[2]=='0')?0:1; - _func[3] = (func[3]=='0')?0:1; + _func = func; _layer = NO_LAYER; } inline uint8_t func(uint8_t left, uint8_t right) { @@ -34,9 +35,9 @@ typedef struct Gate { } void print(int id) { - printf ("gate %d: l:%d, r:%d, o:%d, func:%d%d%d%d\n", id, _left, _right, _out, _func[0], _func[1], _func[2], _func[3] ); + printf ("gate %d: l:%lu, r:%lu, o:%lu, func:%d%d%d%d\n", id, _left, _right, _out, _func[0], _func[1], _func[2], _func[3] ); } -} Gate; +}; #endif diff --git a/BMR/Key.cpp b/BMR/Key.cpp index 02fa62b7..3d7735bd 100644 --- a/BMR/Key.cpp +++ b/BMR/Key.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Key.cpp * - * Created on: Oct 27, 2015 - * Author: marcel */ @@ -17,7 +17,7 @@ ostream& operator<<(ostream& o, const Key& key) ostream& operator<<(ostream& o, const __m128i& x) { o.fill('0'); - o << hex; + o << hex << noshowbase; for (int i = 0; i < 2; i++) { o.width(16); @@ -27,26 +27,11 @@ ostream& operator<<(ostream& o, const __m128i& x) { return o; } -Key& Key::operator=(const Key& other) { - r= other.r; -// memcpy(&r, &other.r, sizeof(r)); - return *this; -} - -bool Key::operator==(const Key& other) { - __m128i neq = _mm_xor_si128(r, other.r); - return _mm_test_all_zeros(neq,neq); -} - -Key& Key::operator-=(const Key& other) { - r ^= other.r; - return *this; -} - -Key& Key::operator+=(const Key& other) { - r ^= other.r; - return *this; -} +//Key& Key::operator=(const Key& other) { +// r= other.r; +//// memcpy(&r, &other.r, sizeof(r)); +// return *this; +//} #else //__PRIME_FIELD__ is defined diff --git a/BMR/Key.h b/BMR/Key.h index 555a401d..e72e5ff8 100644 --- a/BMR/Key.h +++ b/BMR/Key.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Key.h * - * Created on: Oct 27, 2015 - * Author: marcel */ #ifndef COMMON_INC_KEY_H_ @@ -13,7 +13,7 @@ #include #include -#include "proto_utils.h" +#include "Tools/FlexBuffer.h" using namespace std; @@ -23,21 +23,63 @@ class Key { public: __m128i r; - Key() : r(_mm_set1_epi64x(0)) {} - Key(long long a) : r(_mm_set1_epi64x(a)) {} - Key(const Key& other) {r= other.r;} + Key() {} + Key(long long a) : r(_mm_cvtsi64_si128(a)) {} + Key(long long a, long long b) : r(_mm_set_epi64x(a, b)) {} + Key(__m128i r) : r(r) {} +// Key(const Key& other) {r= other.r;} - Key& operator=(const Key& other); +// Key& operator=(const Key& other); bool operator==(const Key& other); + bool operator!=(const Key& other) { return !(*this == other); } Key& operator-=(const Key& other); Key& operator+=(const Key& other); + + Key operator^(const Key& other) const { return r ^ other.r; } + Key operator^=(const Key& other) { r ^= other.r; return *this; } + + void serialize(SendBuffer& output) const { output.serialize(r); } + void serialize_no_allocate(SendBuffer& output) const { output.serialize_no_allocate(r); } + + bool get_signal() { return _mm_cvtsi128_si64(r) & 1; } + + template + T get() const; }; ostream& operator<<(ostream& o, const Key& key); ostream& operator<<(ostream& o, const __m128i& x); +inline bool Key::operator==(const Key& other) { + __m128i neq = _mm_xor_si128(r, other.r); + return _mm_test_all_zeros(neq,neq); +} + +inline Key& Key::operator-=(const Key& other) { + r ^= other.r; + return *this; +} + +inline Key& Key::operator+=(const Key& other) { + r ^= other.r; + return *this; +} + +template <> +inline unsigned long Key::get() const +{ + return _mm_cvtsi128_si64(r); +} + +template <> +inline __m128i Key::get() const +{ + return r; +} + + #else //__PRIME_FIELD__ is defined const __uint128_t MODULUS= 0xffffffffffffffffffffffffffffff61; diff --git a/BMR/Party.cpp b/BMR/Party.cpp index ad86d66f..c938dd99 100644 --- a/BMR/Party.cpp +++ b/BMR/Party.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Party.cpp * - * Created on: Feb 15, 2016 - * Author: bush */ #include "Party.h" @@ -18,217 +18,212 @@ #include "proto_utils.h" #include "msg_types.h" #include "prf.h" +#include "BooleanCircuit.h" +#include "Math/Setup.h" #ifdef __PURE_SHE__ #include "mpirxx.h" #endif +ProgramParty* ProgramParty::singleton = 0; + + +BaseParty::BaseParty(party_id_t id) : _id(id) +{ +#ifdef DEBUG_PRNG_PARTY + octet seed[SEED_SIZE]; + memset(seed, 0, sizeof(seed)); + seed[0] = id; + prng.SetSeed(seed); +#endif +} + +BaseParty::~BaseParty() +{ +} + Party::Party(const char* netmap_file, // required to init Node const char* circuit_file, // required to init BooleanCircuit party_id_t id, const std::string input, int numthreads, int numtries - ) :_id(id), + ) :BaseParty(id), _all_input(input), _NUMTHREADS(numthreads), _NUMTRIES(numtries) { _circuit = new BooleanCircuit( circuit_file ); + _circuit->party = this; _G = _circuit->NumGates(); - _N = _circuit->NumParties(); +#ifndef N_PARTIES + _N = _circuit->NumParties(); +#endif _W = _circuit->NumWires(); _OW = _circuit->NumOutWires(); _IO = _circuit->_num_input_wires; - _circuit->_masks = new char[_W]; + resize_registers(); #ifdef __PURE_SHE__ init_modulos(); #endif - _initialize_input(); + reset(); _generate_prf_inputs(); - _allocate_prf_outputs(); - _allocate_input_wire_keys(); - _allocate_external_values(); + init(netmap_file, id, _N); _num_externals_msg_received = {0};//ATOMIC_VAR_INIT(0); _num_inputkeys_msg_received = {0};//ATOMIC_VAR_INIT(0); - printf("netmap_file: %s\n", netmap_file); - if (0 == strcmp(netmap_file, LOOPBACK_STR)) { - _node = new Node( NULL, id, this , _N+1); - } else { - _node = new Node( netmap_file, id, this ); - } -} - -void Party::_allocate_external_values() -{ - _circuit->_externals = (char*)malloc(_W); - memset(_circuit->_externals,NO_SIGNAL,_W); -} - -void Party::_allocate_input_wire_keys () -{ - _input_wire_keys_msg_sz = INPUT_KEYS_MSG_TYPE_SIZE+_IO*sizeof(Key); - _input_wire_keys_msg = (char*)malloc(_input_wire_keys_msg_sz); - memset(_input_wire_keys_msg, 0, _input_wire_keys_msg_sz); } void Party::_initialize_input() { party_t me = _circuit->_parties[_id]; std::string my_input = _all_input.substr(me.wires, me.n_wires); - _input = new char[me.n_wires+1]; + _input.resize(me.n_wires); const char* input = my_input.c_str(); - memcpy(_input, input, me.n_wires); + memcpy(_input.data(), input, me.n_wires); - for(int i=0; i locker(global_lock); switch(message_type) { case TYPE_KEYS: { +#ifdef DEBUG_STEPS printf("TYPE_KEYS\n"); - unsigned int keys_sz = 2*_W*_N*sizeof(Key); - _circuit->_keys = (Key*)malloc(keys_sz); - memcpy(_circuit->_keys, message+MSG_KEYS_HEADER_SZ, keys_sz); -// phex(_circuit->Keys(), 2* _W * _N * sizeof(Key)); -// printf("\n"); -// _print_keys(); - - _compute_prfs_outputs(); -// _print_prfs(); +#endif +#ifdef DEBUG2 + cout << "received keys" << endl; + phex(message, len); +#endif + get_buffer(TYPE_PRF_OUTPUTS); + _compute_prfs_outputs((Key*)(message + MSG_KEYS_HEADER_SZ)); _send_prfs(); // printf("sent prfs\n"); break; } case TYPE_MASK_INPUTS: { +#ifdef DEBUG_STEPS printf("TYPE_MASK_INPUTS\n"); - _generate_external_values_msg(message+sizeof(MSG_TYPE)); +#endif + input_masks.insert(input_masks.end(), message + sizeof(MSG_TYPE), message + len); +#ifdef DEBUG_COMM + cout << "got " << dec << input_masks.size() << " input masks" << endl; +#endif + input_mask = input_masks.begin(); break; } case TYPE_MASK_OUTPUT: { +#ifdef DEBUG_STEPS printf("TYPE_MASK_OUTPUT\n"); - memcpy(_circuit->Masks()+_circuit->OutWiresStart(), message+sizeof(MSG_TYPE), _OW); - // TODO: only test! -// phex(_circuit->Masks(), _W); +#endif +#ifdef DEBUG_OUTPUT_MASKS + cout << "receiving " << msg.left() << " output masks" << endl; +#endif + mask_output(msg); break; } case TYPE_GARBLED_CIRCUIT: { +#ifdef DEBUG_STEPS printf("TYPE_GARBLED_CIRCUIT\n"); - unsigned int garbled_tbl_sz = _G*4*_N*sizeof(Key); - _circuit->_garbled_tbl = (Key*)malloc(garbled_tbl_sz); - _circuit->_garbled_tbl_copy = (Key*)malloc(garbled_tbl_sz); - memcpy(_circuit->_garbled_tbl, message+sizeof(MSG_TYPE), garbled_tbl_sz); - memcpy(_circuit->_garbled_tbl_copy, message+sizeof(MSG_TYPE), garbled_tbl_sz); +#endif +#ifdef DEBUG2 + phex(message, len); +#endif +#ifdef DEBUG_COMM + cout << "got " << len << " bytes for " << get_garbled_tbl_size() << " gates" << endl; +#endif + if ((len - 4) != 4 * _N * sizeof(Key) * get_garbled_tbl_size()) + throw runtime_error("wrong size of garbled table"); + store_garbled_circuit(msg); // printf("\nGarbled Table\n\n"); // _printf_garbled_table(); - char garbled_circuit_cs = cs((char*)_circuit->_garbled_tbl , garbled_tbl_sz); - printf ("\ngarbled_circuit_cs = %d\n", garbled_circuit_cs); +// char garbled_circuit_cs = cs((char*)_garbled_tbl , garbled_tbl_sz); +// printf ("\ngarbled_circuit_cs = %d\n", garbled_circuit_cs); - char* received_gc_msg = new char[sizeof(MSG_TYPE)]; - fill_message_type(received_gc_msg, TYPE_RECEIVED_GC); - _node->Send(SERVER_ID, received_gc_msg, sizeof(MSG_TYPE)); + _node->Send(SERVER_ID, get_buffer(TYPE_RECEIVED_GC)); break; } case TYPE_EXTERNAL_VALUES: { //this is done by party 1 only -// printf("TYPE_EXTERNAL_VALUES from %d\n",from); +#ifdef DEBUG_STEPS + printf("TYPE_EXTERNAL_VALUES from %d\n",from); +#endif _process_external_received(message+sizeof(MSG_TYPE), from); - - int num_received; - { - std::unique_lock locker(_process_externals_mx); - num_received = ++_num_externals_msg_received; - } - if(num_received == _N-1) { - char* all_externals = new char[_IO+sizeof(MSG_TYPE)]; - fill_message_type(all_externals, TYPE_ALL_EXTERNAL_VALUES); - memcpy(all_externals+sizeof(MSG_TYPE), _circuit->_externals,_IO); - _node->Broadcast2(all_externals, _IO+sizeof(MSG_TYPE)); -// printf("sending all externals\n"); -// phex(all_externals+sizeof(MSG_TYPE), _IO); - } break; } case TYPE_ALL_EXTERNAL_VALUES: { -// printf("TYPE_ALL_EXTERNAL_VALUES\n"); -// phex(message+sizeof(MSG_TYPE), _IO); +#ifdef DEBUG_STEPS + printf("TYPE_ALL_EXTERNAL_VALUES\n"); +#endif _process_all_external_received(message+sizeof(MSG_TYPE)); - fill_message_type(_input_wire_keys_msg, TYPE_KEY_PER_IN_WIRE); - _node->Send(1, _input_wire_keys_msg, _input_wire_keys_msg_sz); break; } case TYPE_KEY_PER_IN_WIRE: { -// printf("TYPE_KEY_PER_IN_WIRE from %d\n", from); +#ifdef DEBUG_STEPS + printf("TYPE_KEY_PER_IN_WIRE from %d\n", from); +#endif _process_input_keys((Key*)(message+INPUT_KEYS_MSG_TYPE_SIZE), from); - int num_received; - { - std::unique_lock locker(_process_keys_mx); - num_received = ++_num_inputkeys_msg_received; - } -// printf("num_received = %d\n",num_received); - if(num_received == _N-1) - { -// printf("received input keys from everyone\n"); - unsigned int all_keys_msg_sz = 2*_N*_IO*sizeof(Key)+INPUT_KEYS_MSG_TYPE_SIZE; - char* all_keys_msg = new char[all_keys_msg_sz]; - fill_message_type(all_keys_msg, TYPE_ALL_KEYS_PER_IN_WIRE); - memcpy(all_keys_msg+INPUT_KEYS_MSG_TYPE_SIZE, _circuit->_keys, 2*_N*_IO*sizeof(Key)); -// printf("all input keys:\n"); -// _print_input_keys_checksum(); -// phex(all_keys_msg+INPUT_KEYS_MSG_TYPE_SIZE, 2*_N*_IO*sizeof(Key)); - _node->Broadcast2(all_keys_msg, all_keys_msg_sz); - _check_evaluate(); - } - - break; } case TYPE_ALL_KEYS_PER_IN_WIRE: { -// printf("TYPE_ALL_KEYS_PER_IN_WIRE\n"); +#ifdef DEBUG_STEPS + printf("TYPE_ALL_KEYS_PER_IN_WIRE\n"); +#endif _process_all_input_keys(message+INPUT_KEYS_MSG_TYPE_SIZE); - printf("all input keys:\n"); -// phex(message+INPUT_KEYS_MSG_TYPE_SIZE, 2*_N*_IO*sizeof(Key)); -// _print_input_keys_checksum(); - _check_evaluate(); break; } case TYPE_LAUNCH_ONLINE: { +#ifdef DEBUG_STEPS printf("TYPE_LAUNCH_ONLINE\n"); +#endif + cout << "Launching online phase at " << timer.elapsed() << endl; + _node->print_waiting(); + // store a token item in case it's needed just before ending the program + ReceivedMsg msg; + // to avoid copying from address 0 + msg.resize(1); + // for valgrind + msg.data()[0] = 0; + // token input round + store_garbled_circuit(msg); + online_timer.start(); _start_online_net = GET_TIME(); -// _node->Broadcast2(_external_values_msg, _external_values_msg_sz); - if(_id!=1) { -// printf("sending my externals:\n"); -// phex(_external_values_msg+sizeof(MSG_TYPE), _circuit->Party(_id).n_wires); - _node->Send(1,_external_values_msg, _external_values_msg_sz); - } + start_online_round(); break; } case TYPE_CHECKSUM: @@ -237,21 +232,55 @@ void Party::NewMessage(int from, char* message, unsigned int len) printf("got checksum = %d\n", message[sizeof(MSG_TYPE)]); break; } + case TYPE_SPDZ_WIRES: + receive_spdz_wires(msg); + break; + case TYPE_DELTA: + msg.unserialize(delta); + break; default: { printf("UNDEFINED\n"); printf("got undefined message\n"); phex(message, len); + break; } } +#ifdef DEBUG_STEPS + cout << "done with " << message_type_names[message_type] << " from " << from << endl; +#endif +} + +void Party::start_online_round() +{ + _generate_external_values_msg(); +// _node->Broadcast2(_external_values_msg, _external_values_msg_sz); + if(_id!=1) { +// printf("sending my externals:\n"); +// phex(_external_values_msg+sizeof(MSG_TYPE), _circuit->Party(_id).n_wires); + _node->Send(1,_external_values_msg); + } +} + +void Party::store_garbled_circuit(ReceivedMsg& msg) +{ + auto end = get_garbled_tbl_end(); + for (auto it = _garbled_tbl.begin(); it != end; it++) + { + it->unserialize(msg, _N); +#ifdef DEBUG + it->print(); +#endif + } } void Party::_check_evaluate() { + load_garbled_circuit(); _end_online_net = GET_TIME(); printf("Network time: "); - PRINT_DIFF(_start_online_net, _end_online_net); + PRINT_DIFF(&_start_online_net, &_end_online_net); #ifdef __PRIME_FIELD__ printf("this implementation uses PRIME FIELD\n"); #endif @@ -259,15 +288,15 @@ void Party::_check_evaluate() printf("\n\npress for EVALUATING\n\n"); getchar(); - exec_props_t* execs = new exec_props_t[_NUMTHREADS+1]; + vector execs(_NUMTHREADS+1); unsigned long diff; for (int ntry=1; ntry<=_NUMTRIES; ntry++) { for(int nthreads=1; nthreads<=_NUMTHREADS; nthreads+=1) { - memcpy(_circuit->_garbled_tbl, _circuit->_garbled_tbl_copy, _G*4*_N*sizeof(Key)); +// _garbled_tbl = _garbled_tbl_copy; // printf("num threads = %d\n", nthreads); - CALLGRIND_START_INSTRUMENTATION; - struct timeval* b; +// CALLGRIND_START_INSTRUMENTATION; + struct timeval b; if(nthreads == 1) { b = GET_TIME(); // printf("Linear evaluation\n"); @@ -277,13 +306,13 @@ void Party::_check_evaluate() // printf("Non linear evaluation\n"); _circuit->EvaluateByLayer(nthreads, _id); } - CALLGRIND_STOP_INSTRUMENTATION; +// CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_DUMP_STATS; - struct timeval* a = GET_TIME(); + struct timeval a = GET_TIME(); // _circuit->Output(); // printf("Eval time: "); - diff = GET_DIFF(b, a); + diff = GET_DIFF(&b, &a); // printf("#threads = %d, time = %lu\n", nthreads, diff); execs[nthreads].acc += diff; if (diff < execs[nthreads].min || execs[nthreads].min==0) { @@ -292,7 +321,9 @@ void Party::_check_evaluate() } } +#ifdef DEBUG _circuit->Output(); +#endif //getting the best results unsigned long minmin = execs[1].min; @@ -312,10 +343,12 @@ void Party::_check_evaluate() } printf("\nRESULTS SUM:\n"); printf("Got minimal time with %d threads: %ld\n", best_minmin, minmin); - printf("Got minimal AVERAGE time with %d threads: %ld\n", best_avgmin, avgmin/_NUMTRIES); + printf("Got minimal AVERAGE time with %d threads: %llu\n", best_avgmin, avgmin/_NUMTRIES); + fflush(0); + done(); } -void Party::Start() +void BaseParty::Start() { _node->Start(); } @@ -323,133 +356,47 @@ void Party::Start() void Party::_generate_prf_inputs() { - size_t size_of_inputs = _G*2*_N*16; - char * prf_inputs = new char[size_of_inputs]; //G*2*n*128bit - memset(prf_inputs, 0, size_of_inputs); - - /* fill out this buffer s.t. first 4 bytes are the extension (0/1), - * next 4 bytes are gate_id and next 4 bytes are party id. - * For the first half we dont need to fill the extension because - * it is zero anyway. - */ - unsigned int* prf_input_index = (unsigned int*)prf_inputs; //easier to refer as integers - - for(unsigned int e=0; e<=1; e++) { - for (gate_id_t g=1; g<=_G; g++) { - for(party_id_t j=1; j<=_N; j++) { -// printf("e,g,j=%u,%u,%u\n",e,g,j); - *prf_input_index = e; - *(prf_input_index+1) = g; - *(prf_input_index+2) = j; - prf_input_index+=4; - } - } + resize_garbled_tbl(); + for (gate_id_t g=1; g<=_G; g++) + { + _garbled_tbl[g-1].init_inputs(g, _N); } -// phex(prf_inputs, size_of_inputs); - - _circuit->PrfInputs(prf_inputs); } -void Party::_allocate_prf_outputs() { - unsigned int prf_output_size = (PRFS_PER_PARTY(_G, _N)*sizeof(Key) + RESERVE_FOR_MSG_TYPE ) *_N ; - void* prf_outputs = malloc(prf_output_size); - memset(prf_outputs,0,prf_output_size); - _circuit->Prfs((char*)prf_outputs); - -// printf("prf_output_size = %u\n",prf_output_size); -// printf("prf_outputs = %p-%p\n",prf_outputs, prf_outputs+prf_output_size); -} - -void Party::_compute_prfs_outputs() +void Party::_compute_prfs_outputs(Key* keys) { - unsigned int prf_outputs_offset = ( PRFS_PER_PARTY(_G,_N)*sizeof(Key) + RESERVE_FOR_MSG_TYPE )*(_id-1); - char* party_prf_outputs_starting_point = _circuit->Prfs() + prf_outputs_offset; - char* prf_outputs_index = party_prf_outputs_starting_point + RESERVE_FOR_MSG_TYPE; + receive_keys(keys); + for(gate_id_t g=1; g<=_G; g++) { + const Register* in_wires[2] = {®isters[_circuit->_gates[g]._left], ®isters[_circuit->_gates[g]._right]}; + _garbled_tbl[g-1].compute_prfs_outputs(in_wires, _id, buffers[TYPE_PRF_OUTPUTS], g); + } + printf("\n\n"); +} -// printf("party_prf_outputs_starting_point = %p\n",party_prf_outputs_starting_point); - - for(gate_id_t g=1; g<=_G; g++) { - wire_id_t in_wires[2] = {_circuit->_gates[g]._left, _circuit->_gates[g]._right}; - for(int w=0; w<=1; w++) { - for (int b=0; b<=1; b++) { - for (int e=0; e<=1; e++) { - //TODO optimize by computing for all j's together - for (int j=1; j<= _N; j++) { - Key* key = _circuit->_key(_id, in_wires[w], b); - char* input = _circuit->_input(e, g, j); - PRF_single(key,input, prf_outputs_index); -#ifdef __PRIME_FIELD__ - ((Key*)prf_outputs_index)->adjust(); +void BaseParty::_send_prfs() { + _node->Send(SERVER_ID, buffers[TYPE_PRF_OUTPUTS]); +#ifdef DEBUG2 + printf("Send PRFs:\n"); + phex(buffers[TYPE_PRF_OUTPUTS]); #endif - prf_outputs_index += RESERVE_FOR_MSG_TYPE; - } - } - } - } - } -// printf("\n\n"); -// phex(party_prf_outputs_starting_point, RESERVE_FOR_MSG_TYPE); -// printf("\n"); -// phex(party_prf_outputs_starting_point+RESERVE_FOR_MSG_TYPE, PRFS_PER_PARTY(G,N)*sizeof(Key)); -} - -void Party::_send_prfs() { - unsigned int prfs_size = PRFS_PER_PARTY(_G,_N)*sizeof(Key); - unsigned int prf_outputs_offset = (prfs_size + RESERVE_FOR_MSG_TYPE) * (_id-1); - - char* party_prf_outputs_starting_point = _circuit->Prfs() + prf_outputs_offset + RESERVE_FOR_MSG_TYPE - sizeof(MSG_TYPE); - fill_message_type(party_prf_outputs_starting_point, TYPE_PRF_OUTPUTS); - - _node->Send(SERVER_ID, party_prf_outputs_starting_point, prfs_size+sizeof(MSG_TYPE)); -// printf("\n"); -// phex(party_prf_outputs_starting_point, prfs_size+sizeof(MSG_TYPE)); -} - -void Party::_print_prfs() -{ - unsigned int prf_outputs_offset = ( PRFS_PER_PARTY(_G,_N)*sizeof(Key) + RESERVE_FOR_MSG_TYPE )*(_id-1); - char* party_prf_outputs_starting_point = _circuit->Prfs() + prf_outputs_offset; - char* prf_outputs_index = party_prf_outputs_starting_point + RESERVE_FOR_MSG_TYPE; - - for (gate_id_t g=1; g<=_G; g++) { - wire_id_t in_wires[2] = {_circuit->_gates[g]._left, _circuit->_gates[g]._right}; - for(int w=0; w<=1; w++) { - for (int b=0; b<=1; b++) { - for (int e=0; e<=1; e++) { -// phex(prf_outputs_index, _N*sizeof(Key)); -// printf("F_k^%d_{%u,%d}(%d,%u,1-n) = ", _id, in_wires[w], b, e, g); - for(party_id_t j=1; j<=_N; j++) { - Key k = *((Key*)(prf_outputs_index)); -// std::cout << k << " "; - prf_outputs_index += sizeof(Key); - } -// std::cout << std::endl<< std::endl; - } - } - } - } } void Party::_print_keys() { for (wire_id_t w=0; w<_IO; w++) { - for(int x=0; x<=1; x++) { - printf("k^%d_{%u,%d}: ",_id,w,x); - Key* key_idx = _circuit->_key(_id,w,x); - std::cout << *key_idx << std::endl; - } + registers[w].keys.print(w, _id); } } void Party::_printf_garbled_table() { - for (gate_id_t g=1; g<=_G; g++) { + for (gate_id_t g=1; g<=get_garbled_tbl_size(); g++) { std::cout << "gate " << g << std::endl; for(int entry=0; entry<4; entry++) { for(party_id_t i=1; i<=_N; i++) { - Key* k = _circuit->_garbled_entry(g, entry); - std::cout << *(k+i-1) << " "; + KeyVector& k = _garbled_entry(g, entry); + std::cout << k[i-1] << " "; } std::cout << std::endl; } @@ -461,7 +408,7 @@ void Party::_print_keys_of_party(Key *keys, int id) { printf("\nkeys for party %d", id); for(wire_id_t w=0; w<_IO; w++) { - printf("k^%d_%d: ", id, w); + printf("k^%d_%lu: ", id, w); std::cout << keys[w] << std::endl; } } @@ -469,62 +416,139 @@ void Party::_print_keys_of_party(Key *keys, int id) void Party::_print_input_keys_msg() { for(wire_id_t w=0; w<_IO; w++) { - std::cout << *(Key*)(_input_wire_keys_msg+INPUT_KEYS_MSG_TYPE_SIZE+w*sizeof(Key)) << std::endl; + std::cout << *(Key*)(_input_wire_keys_msg.data()+INPUT_KEYS_MSG_TYPE_SIZE+w*sizeof(Key)) << std::endl; } } - -void Party::_generate_external_values_msg(char *masks) +void Party::_generate_external_values_msg() { - party_t me = _circuit->_parties[_id]; - wire_id_t s = me.wires; //the beginning of my wires - wire_id_t n = me.n_wires; // number of my wires - _external_values_msg_sz = sizeof(MSG_TYPE) + n; - _external_values_msg = (char*)malloc (_external_values_msg_sz); + _initialize_input(); + prepare_input_regs(_id); + _external_values_msg.clear(); fill_message_type(_external_values_msg, TYPE_EXTERNAL_VALUES); - char *exv_msg = _external_values_msg+sizeof(MSG_TYPE); - for(wire_id_t i=0; i_externals[w] = exv_msg[i] = masks[i]^_input[i]; - *(_circuit->_key(_id, w, 1-exv_msg[i])) = 0; + unsigned int n = (*input_regs)[_id].size(); +#ifdef DEBUG_ROUNDS + cout << dec << _input.size() << "/" << n << " inputs" << " in round " + << input_regs.get_i() << endl; +#endif + if (n != _input.size()) + throw runtime_error("number of inputs doesn't match"); + for(unsigned int i=0; i_parties[from]; - wire_id_t s = sender.wires; //the beginning of my wires - wire_id_t n = sender.n_wires; // number of my wires - char* exv = _circuit->_externals; + prepare_input_regs(from); // printf("received externals from %d\n", from); // phex(externals, n); - - for(unsigned int i=0; i_key(_id,w,1-exv[w])) = 0; + for(unsigned int i=0; i<(*input_regs)[from].size(); i++) { + get_reg((*input_regs)[from][i]).set_external(externals[i]); } +#ifdef DEBUG_VALUES + cout << "externals from " << from << ":\t"; + print_bit_array(externals, (*input_regs)[from].size()); + cout << "masks:\t\t\t"; + print_masks((*input_regs)[from]); + cout << "outputs:\t\t"; + print_masks((*input_regs)[from]); + cout << "on registers:" << endl; + print_indices((*input_regs)[from]); +#endif + + size_t num_received; + { + std::unique_lock locker(_process_externals_mx); + num_received = ++_num_externals_msg_received; + } + if(num_received == _N-1) { + _num_externals_msg_received = 0; + SendBuffer& buffer = get_buffer(TYPE_ALL_EXTERNAL_VALUES); + int w = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + vector& regs = (*input_regs)[i+1]; + for (unsigned int j = 0; j < regs.size(); j++) + { + buffer.push_back(registers[regs[j]].get_external()); + w++; + } + } + _node->Broadcast2(buffer); +// printf("sending all externals\n"); +// phex(all_externals+sizeof(MSG_TYPE), _IO); + } } void Party::_process_all_external_received(char* externals) { - memcpy(_circuit->_externals, externals, _IO); - Key* keys_msg = (Key*)(_input_wire_keys_msg+INPUT_KEYS_MSG_TYPE_SIZE); - for(wire_id_t w=0; w<_IO; w++) { - keys_msg[w] = * _circuit->_key(_id,w,_circuit->_externals[w]); +// phex(message+sizeof(MSG_TYPE), _IO); + _input_wire_keys_msg.clear(); + fill_message_type(_input_wire_keys_msg, TYPE_KEY_PER_IN_WIRE); + _input_wire_keys_msg.resize(INPUT_KEYS_MSG_TYPE_SIZE); + + int w = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + vector& regs = (*input_regs)[i+1]; + for (unsigned int j = 0; j < regs.size(); j++) + { + get_reg(regs[j]).set_external(externals[w]); + get_reg(regs[j]).external_key(_id).serialize(_input_wire_keys_msg); +#ifdef DEBUG + printf("k^%d_{%u,%d}=", _id,w,registers[regs[j]].get_external()); + std::cout << registers[regs[j]].external_key(_id) << std::endl; +#endif + w++; + } +#ifdef DEBUG_VALUES + cout << "on registers:" << endl; + for (unsigned j = 0; j < (*input_regs)[i + 1].size(); j++) + cout << (*input_regs)[i + 1][j] << " "; + cout << endl; + cout << "externals from " << (i + 1) << ":\t"; + print_bit_array(externals, regs.size()); + cout << "masks:\t\t\t"; + print_masks(output_regs); + cout << "outputs:\t\t"; + print_outputs(output_regs); +#endif } -// for(wire_id_t w=0; w<_IO; w++) { -// printf("k^%d_{%u,%d}=", _id,w,_circuit->_externals[w]); -// std::cout << keys_msg[w] << std::endl; -// } + _node->Send(1, _input_wire_keys_msg); +#ifdef DEBUG2 + printf("input wire keys:\n"); + phex(_input_wire_keys_msg); +#endif } //void Party::_process_input_keys(char* keys, party_id_t from) @@ -546,10 +570,50 @@ void Party::_process_input_keys(Key* keys, party_id_t from) // std::cout << keys[w] << std::endl; // } - char *exv = _circuit->_externals; - for(wire_id_t w=0; w<_IO; w++) { - *(_circuit->_key(from,w,exv[w])) = keys[w]; + int w = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + for (unsigned int j = 0; j < (*input_regs)[i+1].size(); j++) + { + get_reg((*input_regs)[i+1][j]).set_external_key(from, keys[w]); + w++; + } } + + size_t num_received; + { + std::unique_lock locker(_process_keys_mx); + num_received = ++_num_inputkeys_msg_received; + } +// printf("num_received = %d\n",num_received); + if(num_received == _N-1) + { + _num_inputkeys_msg_received = 0; +#ifdef DEBUG_STEPS + printf("received input keys from everyone\n"); +#endif + SendBuffer& buffer = get_buffer(TYPE_ALL_KEYS_PER_IN_WIRE); + buffer.resize(INPUT_KEYS_MSG_TYPE_SIZE); + int w = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + for (unsigned int j = 0; j < (*input_regs)[i+1].size(); j++) + { + get_reg((*input_regs)[i+1][j]).keys.serialize(buffer); + w++; + } + } +#ifdef DEBUG2 + printf("all input keys:\n"); + _print_input_keys_checksum(); + phex(buffer); +#endif + _node->Broadcast2(buffer); + _check_evaluate(); + } + } @@ -558,49 +622,336 @@ void Party::_process_all_input_keys(char* keys) /* keys: a block containing 2*_N keys for each input wire so the * receiver only has to copy one time. */ - memcpy(_circuit->_keys, keys, _IO*2*_N*sizeof(Key)); + int w = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + for (unsigned int j = 0; j < (*input_regs)[i+1].size(); j++) + { + get_reg((*input_regs)[i+1][j]).set_eval_keys((Key*)keys+w*2*_N, _N, _id - 1); + w++; + } + } + +#ifdef DEBUG + printf("all input keys:\n"); +// phex(message+INPUT_KEYS_MSG_TYPE_SIZE, 2*_N*_IO*sizeof(Key)); + _print_input_keys_checksum(); +#endif + _check_evaluate(); } void Party::_print_input_keys_checksum() { - for (wire_id_t w=0; w<_IO; w++) { - char x = _circuit->_externals[w]; - for(int x=0; x<=1; x++) { - printf("k^I_{%u,%d}: ",w,x); - for (party_id_t i=1; i<=_N; i++) { - Key* key_idx = _circuit->_key(i,w,x); - std::cout << *key_idx << " "; - } - std::cout << std::endl; + int w = 0; + for (unsigned int i = 0; i < (*input_regs).size(); i++) + for (unsigned int j = 0; j < (*input_regs)[i].size(); j++) + registers[(*input_regs)[i][j]].print_input(w++); +} + +void Party::mask_output(ReceivedMsg& msg) +{ + char* masks = msg.consume(0); + size_t n_masks = msg.left(); + prepare_output_regs(); + if (n_masks != output_regs.size()) + throw runtime_error("number of masks doesn't match"); + for (unsigned int i = 0; i < output_regs.size(); i++) + get_reg(output_regs[i]).set_mask(masks[i]); +#ifdef DEBUG_VALUES + cout << "received output masks in registers:" << endl; + vector externals(output_regs.size()), outputs(output_regs.size()); + for (unsigned int i = 0; i < output_regs.size(); i++) + { + externals[i] = get_reg(output_regs[i]).get_external_no_check(); + outputs[i] = get_reg(output_regs[i]).get_output_no_check(); + cout << output_regs[i] << " "; + } + cout << endl; + cout << "masks:\t\t\t"; + print_bit_array(masks, output_regs.size()); + cout << "externals:\t\t"; + print_bit_array(externals); + cout << "outputs:\t\t"; + print_bit_array(outputs); +#endif +} + +void Party::receive_keys(Key* keys) { + resize_registers(); + for (size_t w = 0; w < _W; w++) + { + registers[w].init(_N); + for (int i = 0; i < 2; i++) + registers[w].keys[i][_id - 1] = *(keys + w * 2 + i); + } +#ifdef DEBUG + _print_keys(); +#endif +} + +int Party::get_n_inputs() { + int res = 0; + for (size_t i = 0; i < _N; i++) + { + prepare_input_regs(i + 1); + vector& regs = (*input_regs)[i+1]; + res += regs.size(); + } + return res; +} + +void BaseParty::done() { + cout << "Online phase took " << online_timer.elapsed() << " seconds" << endl; + _node->Send(SERVER_ID, get_buffer(TYPE_DONE)); + _node->Stop(); +} + +ProgramParty::ProgramParty(int argc, char** argv) : + BaseParty(-1), keys_for_prf(0), + spdz_storage(0), garbled_storage(0), spdz_counters(SPDZ_OP_N), + machine(dynamic_memory), + processor(machine), prf_machine(dynamic_memory), + prf_processor(prf_machine), + MC(0) +{ + if (argc < 3) + { + cerr << "Usage: " << argv[0] << " [netmap]" << endl; + exit(1); + } + + _id = atoi(argv[1]); + ifstream file((string("Programs/Bytecode/") + argv[2] + "-0.bc").c_str()); + program.parse(file); + machine.reset(program); + processor.reset(program); + prf_machine.reset(*reinterpret_cast >* >(&program)); + prf_processor.reset(*reinterpret_cast >* >(&program)); + if (singleton) + throw runtime_error("there can only be one"); + singleton = this; + if (argc > 3) + { + int n_parties = init(argv[3], _id); + ifstream netmap(argv[3]); + int tmp; + string tmp2; + netmap >> tmp >> tmp2 >> tmp; + vector hostnames(n_parties); + for (int i = 0; i < n_parties; i++) + { + netmap >> hostnames[i]; + netmap >> tmp; + } + N.init(_id - 1, 5000, hostnames); + } + else + { + int n_parties = init("LOOPBACK", _id); + N.init(_id - 1, 5000, vector(n_parties, "localhost")); + } + prf_output = (char*)new __m128i[PAD_TO_8(get_n_parties())]; + mac_key = prng.get_word() & ((1ULL << GC::Secret::default_length) - 1); + cout << "MAC key: " << hex << mac_key << endl; + ifstream schfile((string("Programs/Schedules/") + argv[2] + ".sch").c_str()); + string curr, prev; + while (schfile.good()) + { + prev = curr; + getline(schfile, curr); + } + cout << "Compiler: " << prev << endl; + P = new Player(N, 0); + if (argc > 4) + threshold = atoi(argv[4]); + else + threshold = 128; + cout << "Threshold for multi-threaded evaluation: " << threshold << endl; +} + +ProgramParty::~ProgramParty() +{ + reset(); + delete[] prf_output; + delete P; + if (MC) + delete MC; + cout << "SPDZ loading: " << spdz_counters[SPDZ_LOAD] << endl; + cout << "SPDZ storing: " << spdz_counters[SPDZ_STORE] << endl; + cout << "SPDZ wire storage: " << 1e-9 * spdz_storage << " GB" << endl; + cout << "Dynamic storage: " << 1e-9 * dynamic_memory.capacity() * + sizeof(GC::Secret::DynamicType) << " GB" << endl; + cout << "Maximum circuit storage: " << 1e-9 * garbled_storage << " GB" << endl; +} + +void ProgramParty::_compute_prfs_outputs(Key* keys) +{ + keys_for_prf = keys; + first_phase(program, prf_processor, prf_machine); +} + +void ProgramParty::reset() +{ + CommonParty::reset(); +} + +void ProgramParty::store_garbled_circuit(ReceivedMsg& msg) +{ + garbled_storage = max(msg.size(), garbled_storage); + garbled_circuits.push(msg); +} + +void ProgramParty::load_garbled_circuit() +{ + if (not garbled_circuits.pop(garbled_circuit)) + throw runtime_error("no garbled circuit available"); + if (not output_masks_store.pop(output_masks)) + throw runtime_error("no output masks available"); +#ifdef DEBUG_OUTPUT_MASKS + cout << "loaded " << output_masks.left() << " output masks" << endl; +#endif +} + +void ProgramParty::start_online_round() +{ + machine.reset_timer(); + _check_evaluate(); +} + +void ProgramParty::_check_evaluate() +{ +#ifdef DEBUG_REGS + print_round_regs(); +#endif + cout << "Online time at evaluation start: " << online_timer.elapsed() + << endl; + GC::BreakType next = GC::TIME_BREAK; + while (next == GC::TIME_BREAK) + { + load_garbled_circuit(); + next = second_phase(program, processor, machine); + } + cout << "Online time at evaluation stop: " << online_timer.elapsed() + << endl; + if (next == GC::TIME_BREAK) + { +#ifdef DEBUG_STEPS + cout << "another round of garbling" << endl; +#endif + } + if (next != GC::DONE_BREAK) + { +#ifdef DEBUG_STEPS + cout << "another round of evaluation" << endl; +#endif + start_online_round(); + } + else + { + Timer timer; + timer.start(); + MC->Check(*P); + cout << "Final check took " << timer.elapsed() << endl; + done(); + } +} + +void ProgramParty::receive_keys(Register& reg) +{ + reg.init(_N); + for (int i = 0; i < 2; i++) + reg.keys[i][_id-1] = *(keys_for_prf++); +#ifdef DEBUG + cout << "receive keys " << reg.get_id() << "(" << ® << ") " << dec << reg.keys[0].size() << endl; + reg.keys.print(reg.get_id(), _id); + cout << "delta " << reg.get_id() << " " << (reg.keys[0][_id-1] ^ reg.keys[1][_id-1]) << endl; +#endif +} + +void ProgramParty::receive_all_keys(Register& reg, bool external) +{ + reg.init(get_n_parties()); + for (int i = 0; i < get_n_parties(); i++) + reg.keys[external][i] = *(keys_for_prf++); +} + +void ProgramParty::input_value(party_id_t from, char value) +{ + if (from == _id) + { + if (value and (1 - value)) + throw runtime_error("invalid input"); + } + throw not_implemented(); +} + +void ProgramParty::receive_spdz_wires(ReceivedMsg& msg) +{ + int op; + msg.unserialize(op); + spdz_wires[op].push_back({}); + size_t l = msg.left(); + spdz_wires[op].back().append((octet*)msg.consume(l), l); + spdz_storage += l; +#ifdef DEBUG_SPDZ_WIRES + cout << "receive " << dec << spdz_wires[op].back().get_length() << "/" + << msg.size() << " bytes for type " << op << endl; +#endif + if (op == SPDZ_MAC) + { + gf2n spdz_mac_key; + spdz_mac_key.unpack(spdz_wires[op].back()); + if (!MC) + { + MC = new Passing_MAC_Check(spdz_mac_key, N, 0); + cout << "MAC key: " << hex << spdz_mac_key << endl; + mac_key = spdz_mac_key; } } } - -/* Gets as an argument a config file with the following format: - * - * - * - */ -int main(int argc, char *argv[]) { - - assert(argc==3); - std::string config_file = argv[1]; - std::ifstream params(config_file); - assert(params.good()); // manages to open the file - party_id_t pid = atoi(argv[2]); - - int numthreads, numtrials; - std::string netmap_path, circuit_path, input; - params >> netmap_path >> circuit_path >> input >> numthreads >> numtrials; - -#ifdef __PRIME_FIELD__ - printf("this implementation uses PRIME FIELD\n"); +void ProgramParty::get_spdz_wire(SpdzOp op, SpdzWire& spdz_wire) +{ + while (true) + { + if (spdz_wires[op].empty()) + throw runtime_error("no SPDZ wires available"); + if (spdz_wires[op].front().done()) + spdz_wires[op].pop_front(); + else + break; + } + spdz_wire.unpack(spdz_wires[op].front(), get_n_parties()); + spdz_counters[op]++; +#ifdef DEBUG_SPDZ_WIRE + cout << "get SPDZ wire of type " << op << ", " << spdz_wires[op].front().left() << " bytes left" << endl; + cout << "mask share for " << get_id() << ": " << spdz_wire.mask << endl; +#endif +} + +void ProgramParty::store_wire(const Register& reg) +{ + wires.serialize(reg.key(get_id(), 0)); +#ifndef FREE_XOR + wires.serialize(reg.key(get_id(), 1)); +#endif +#ifdef DEBUG + cout << "storing wire" << endl; + reg.print(); +#endif +} + +void ProgramParty::load_wire(Register& reg) +{ + wires.unserialize(reg.key(get_id(), 0)); +#ifdef FREE_XOR + reg.key(get_id(), 1) = reg.key(get_id(), 0) ^ get_delta(); +#else + wires.unserialize(reg.key(get_id(), 1)); +#endif +#ifdef DEBUG + cout << "loading wire" << endl; + reg.print(); #endif - - Party* p = new Party(netmap_path.c_str(), circuit_path.c_str(), pid, input, numthreads, numtrials); - p->Start(); - pause(); - - return 0; } diff --git a/BMR/Party.h b/BMR/Party.h index 0121176f..c09b289d 100644 --- a/BMR/Party.h +++ b/BMR/Party.h @@ -1,94 +1,253 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Party.h * - * Created on: Feb 15, 2016 - * Author: bush */ #ifndef PROTOCOL_PARTY_H_ #define PROTOCOL_PARTY_H_ -#include "BooleanCircuit.h" #include #include -#include "Node.h" +#include "Register.h" +#include "GarbledGate.h" +#include "network/Node.h" +#include "CommonParty.h" +#include "SpdzWire.h" +#include "AndJob.h" + +#include "GC/Machine.h" +#include "GC/Program.h" +#include "GC/Processor.h" +#include "GC/Secret.h" +#include "Tools/Worker.h" + +class BooleanCircuit; #define SERVER_ID (0) #define INPUT_KEYS_MSG_TYPE_SIZE (16) // so memory will by alligned +#ifndef N_EVAL_THREADS +// Default Intel desktop processor has 8 half cores. +// This is beneficial if only one AES available per full core. +#define N_EVAL_THREADS (8) +#endif + typedef struct { unsigned long min=0; unsigned long long acc=0; } exec_props_t; -class Party : public NodeUpdatable { +class BaseParty : virtual public CommonParty { +public: + BaseParty(party_id_t id); + virtual ~BaseParty(); + + /* From NodeUpdatable class */ + void NodeReady(); + void NewMessage(int from, ReceivedMsg& msg); + void NodeAborted(struct sockaddr_in* from) { (void)from; } + + void Start(); + + party_id_t get_id() { return _id; } + Key get_delta() { return delta; } + +protected: + party_id_t _id; + +// int _num_evaluation_threads; + struct timeval _start_online_net, _end_online_net; + + vector input_masks; + vector::iterator input_mask; + + Timer online_timer; + + Key delta; + + virtual void _compute_prfs_outputs(Key* keys) = 0; + void _send_prfs(); + + virtual void _process_external_received(char* externals, + party_id_t from) = 0; + virtual void _process_all_external_received(char* externals) = 0; + virtual void _process_input_keys(Key* keys, party_id_t from) = 0; + virtual void _process_all_input_keys(char* keys) = 0; + + virtual void store_garbled_circuit(ReceivedMsg& msg) = 0; + virtual void _check_evaluate() = 0; + + virtual void mask_output(ReceivedMsg& msg) = 0; + + void done(); + + virtual void start_online_round() = 0; + + virtual void receive_spdz_wires(ReceivedMsg& msg) = 0; +}; + +class Party : public BaseParty, public CommonCircuitParty { + friend class BooleanCircuit; + public: Party(const char* netmap_file, const char* circuit_file, party_id_t id, const std::string input, int numthreads=5, int numtries=2); virtual ~Party(); - /* From NodeUpdatable class */ - void NodeReady(); - void NewMessage(int from, char* message, unsigned int len); - void NodeAborted(struct sockaddr_in* from) {} - - void Start(); - /* TEST methods */ private: - party_id_t _id; - Node* _node; - BooleanCircuit* _circuit; - - gate_id_t _G; - party_id_t _N; - wire_id_t _W; - wire_id_t _OW; - wire_id_t _IO; + wire_id_t _IO; std::string _all_input; - char* _input; - char* _external_values_msg; - unsigned int _external_values_msg_sz; + int _NUMTHREADS; + int _NUMTRIES; + + vector _garbled_tbl; + + vector _input; + + SendBuffer _external_values_msg; int _num_externals_msg_received; std::mutex _process_externals_mx; - char* _input_wire_keys_msg; - unsigned int _input_wire_keys_msg_sz; + SendBuffer _input_wire_keys_msg; int _num_inputkeys_msg_received; std::mutex _process_keys_mx; std::mutex _sync_mx; -// int _num_evaluation_threads; - struct timeval* _start_online_net, *_end_online_net; - int _NUMTHREADS; - int _NUMTRIES; +#ifdef __PURE_SHE__ + Key* _sqr_keys; + inline Key* _sqr_key(party_id_t i, wire_id_t w,int b) {return _sqr_keys+ w*2*_num_parties + b*_num_parties + i-1 ; } +#endif + + inline Key& _key(party_id_t i, wire_id_t w,int b) {return registers[w][b][i-1] ; } + inline KeyVector& _garbled_entry(gate_id_t g, int entry) {return _garbled_tbl[g-1][entry];} + vector::iterator get_garbled_tbl_end() { return _garbled_tbl.begin() + garbled_tbl_size; } + void resize_garbled_tbl() { _garbled_tbl.resize(_G, _N); garbled_tbl_size = _G; } void _initialize_input(); void _generate_prf_inputs(); - void _allocate_prf_outputs(); - void _compute_prfs_outputs(); - void _print_prfs(); - void _send_prfs(); + void _compute_prfs_outputs(Key* keys); void _print_keys(); - void _printf_garbled_table(); - void _allocate_external_values(); - void _generate_external_values_msg(char * masks); - void _process_external_received(char* externals, party_id_t from); + void _generate_external_values_msg(); + void _process_external_received(char* externals, + party_id_t from); void _process_all_external_received(char* externals); - inline void _allocate_input_wire_keys(); - void _print_input_keys_msg(); - void _print_keys_of_party(Key *keys, int id); void _print_input_keys_checksum(); void _process_input_keys(Key* keys, party_id_t from); void _process_all_input_keys(char* keys); + void _print_input_keys_msg(); + void _print_keys_of_party(Key *keys, int id); + void _printf_garbled_table(); + + void store_garbled_circuit(ReceivedMsg& msg); + void load_garbled_circuit() {} + void _check_evaluate(); + void receive_keys(Key* keys); + + void receive_spdz_wires(ReceivedMsg& msg) { (void)msg; } + + void start_online_round(); + + void mask_output(ReceivedMsg& msg); + + int get_n_inputs(); }; +class ProgramParty : public BaseParty +{ + friend class PRFRegister; + friend class EvalRegister; + friend class Register; + + char* prf_output; + Key* keys_for_prf; + + deque spdz_wires[SPDZ_OP_N]; + size_t spdz_storage; + size_t garbled_storage; + vector spdz_counters; + + Worker eval_threads[N_EVAL_THREADS]; + AndJob and_jobs[N_EVAL_THREADS]; + + ReceivedMsgStore output_masks_store; + + GC::Memory< GC::Secret::DynamicType > dynamic_memory; + GC::Machine< GC::Secret > machine; + GC::Processor > processor; + GC::Program > program; + + GC::Machine< GC::Secret > prf_machine; + GC::Processor > prf_processor; + + void _compute_prfs_outputs(Key* keys); + + void _process_external_received(char* externals, + party_id_t from) { (void)externals; (void)from; } + void _process_all_external_received(char* externals) { (void)externals; } + void _process_input_keys(Key* keys, party_id_t from) + { (void)keys; (void)from; } + void _process_all_input_keys(char* keys) { (void)keys; } + + void store_garbled_circuit(ReceivedMsg& msg); + void load_garbled_circuit(); + + void _check_evaluate(); + + void receive_keys(Register& reg); + void receive_all_keys(Register& reg, bool external); + + void receive_spdz_wires(ReceivedMsg& msg); + + void start_online_round(); + + void mask_output(ReceivedMsg& msg) { output_masks_store.push(msg); } + +public: + static ProgramParty* singleton; + + ReceivedMsg garbled_circuit; + ReceivedMsgStore garbled_circuits; + + ReceivedMsg output_masks; + + MAC_Check* MC; + Player* P; + Names N; + + int threshold; + + static ProgramParty& s(); + + ProgramParty(int argc, char** argv); + ~ProgramParty(); + + void reset(); + + void input_value(party_id_t from, char value); + + void get_spdz_wire(SpdzOp op, SpdzWire& spdz_wire); + + void store_wire(const Register& reg); + void load_wire(Register& reg); +}; + +inline ProgramParty& ProgramParty::s() +{ + if (singleton) + return *singleton; + else + throw runtime_error("no singleton"); +} + #endif /* PROTOCOL_PARTY_H_ */ diff --git a/BMR/Register.cpp b/BMR/Register.cpp new file mode 100644 index 00000000..20631f90 --- /dev/null +++ b/BMR/Register.cpp @@ -0,0 +1,1094 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Register.cpp + * + */ + +#include "Register.h" +#include "Wire.h" +#include "GarbledGate.h" +#include "Gate.h" +#include "Party.h" +#include "TrustedParty.h" +#include "CommonParty.h" +#include "Register_inline.h" + +#include "prf.h" + +#include "GC/Secret.h" +#include "GC/Processor.h" +#include "Tools/FlexBuffer.h" + +#include + +ostream& EvalRegister::out = cout; + +int Register::counter = 0; + +void Register::init(int n_parties) +{ + keys.init(n_parties); + mask = NO_SIGNAL; + external = NO_SIGNAL; +} + +void Register::init(int rfd, int n_parties) { + (void)rfd; + mask = CommonParty::s().prng.get_uchar(); +#ifdef DEBUG + mask = counter & 1; + counter++; +#endif +#ifdef DEBUG_MASK + mask = 0; +#endif + mask = mask>0 ? 1 : 0; + keys.init(n_parties); + keys.randomize(); +#ifdef KEY_SIGNAL + for (int i = 0; i < 2; i++) + for (size_t j = 0; j < keys[i].size(); j++) + if (keys[i][j].get_signal() != i) + keys[i][j] ^= Key(1); +#endif +} + +void Register::set_eval_keys() +{ + if (external == NO_SIGNAL) + throw exception(); + garbled_entry = keys[external]; +} + +void Register::set_eval_keys(Key* keys, int n_parties, int except) +{ + this->keys.copy_from(keys, n_parties, except); + set_eval_keys(); +} + +void Register::set_external_key(party_id_t i, const Key& key) +{ + check_external(); + garbled_entry[i-1] = key; + keys[external][i-1] = key; + //keys[1-external][i-1] = 0; +} + +void Register::reset_non_external_key(party_id_t i) +{ + check_external(); + keys[1-external][i-1] = 0; +} + +void Register::set_external(char ext) +{ + external = ext; + check_external(); + garbled_entry = keys[external]; +} + +void Register::check_mask() const +{ +#ifdef SIGNAL_CHECK + if (mask * (1 - mask) != 0) + { + if (mask == NO_SIGNAL) + throw runtime_error("no signal in mask"); + else + throw runtime_error("invalid mask"); + } +#endif +} + +void Register::set_mask(char mask) +{ + this->mask = mask; + check_mask(); +} + +void Register::check_external() const +{ +#ifdef SIGNAL_CHECK + if (external * (1 - external) != 0) + { + if (external == NO_SIGNAL) + throw runtime_error("no signal in external value"); + else + throw runtime_error("invalid external value"); + } +#endif +} + +void Register::check_signal_key(int my_id, KeyVector& garbled_entry) +{ + if (garbled_entry[my_id - 1] != keys[get_external()][my_id - 1]) + { + if (garbled_entry[my_id - 1] == keys[1 - get_external()][my_id - 1]) + throw runtime_error("key matches inverted signal"); + else + { + cout << "signal " << (int)get_external() << ", "; + cout << garbled_entry[my_id - 1] << " none of "; + for (int i = 0; i < 2; i++) + cout << keys[i][my_id - 1] << " "; + cout << endl; + throw runtime_error("key doesn't match signal"); + } + } +} + +void Register::print_input(int id) +{ + for (int x = 0; x < 2; x++) + { + printf("k^I_{%u,%d}: ",id,x); + for (unsigned int i = 0; i < keys[x].size(); i++) + std::cout << keys[x][i] << " "; + std::cout << std::endl; + } +} + +template <> +void EvalRegister::andrs(GC::Processor >& processor, + const vector& args) +{ + ProgramParty& party = ProgramParty::s(); + int total = 0; + for (size_t j = 0; j < args.size(); j += 4) + total += args[j]; + if (total < party.threshold) + { + // run in single thread + processor.andrs(args); + return; + } + + int max_gates_per_thread = (total + N_EVAL_THREADS - 1) / N_EVAL_THREADS; + int i_thread = 0, i_gate = 0; + party.and_jobs[0].reset(processor.S, args, 0, party.next_gate(0), + total, party.get_n_parties()); + for (size_t j = 0; j < args.size(); j += 4) + { + AndJob& and_job = party.and_jobs[i_thread]; + GC::Secret& dest = processor.S[args[j + 1]]; + dest.resize_regs(args[j]); + processor.complexity += args[j]; + for (int i = 0; i < args[j]; i++) + { + and_job.gates[i_gate].unserialize(party.garbled_circuit, + party.get_n_parties()); + i_gate++; + } + and_job.end = j + 4; + if (i_gate >= max_gates_per_thread or and_job.end >= args.size()) + { + party.eval_threads[i_thread].request(and_job); + gate_id_t gate_id = party.next_gate(i_gate); + i_gate = 0; + // advance to next thread but only if not on least thread + if(and_job.end < args.size()) + party.and_jobs[++i_thread].reset(processor.S, args, and_job.end, + gate_id, total, party.get_n_parties()); + } + } + + for (int i = 0; i <= i_thread; i++) + party.eval_threads[i].done(); +} + +void EvalRegister::op(const ProgramRegister& left, const ProgramRegister& right, Function func) +{ + (void)func; +#ifdef DEBUG + cout << "eval left " << &left << " " << dec << " " << left.get_id() << endl; + cout << "eval right " << &right << " " << dec << " " << right.get_id() << endl; +#endif + ProgramParty& party = *ProgramParty::singleton; + GarbledGate gate(party.get_n_parties()); + party.next_gate(gate); + gate.unserialize(party.garbled_circuit, party.get_n_parties()); + Register::eval(left, right, gate, party._id, party.prf_output, + get_id(), left.get_id(), right.get_id()); +} + +void Register::eval(const Register& left, const Register& right, GarbledGate& gate, + party_id_t my_id, char* prf_output, int w_o, int w_l, int w_r) +{ + (void)w_o; + (void)w_l; + (void)w_r; + size_t n_parties = CommonParty::singleton->get_n_parties(); + int sig_l = left.get_external(); + int sig_r = right.get_external(); + int entry = 2 * sig_l + sig_r; + +#ifdef DEBUG + gate.print(); + cout << "picking " << entry << endl; +#endif + + garbled_entry = gate[entry]; + int ext_l = entry%2 ? 1 : 0 ; + int ext_r = entry<2 ? 0 : 1 ; + +#ifdef DEBUG + printf("left input"); + phex(gate.input(ext_l, 1), 16); + printf("right input"); + phex(gate.input(ext_r, 1), 16); +#endif + + Key k; + for(party_id_t i=1; i<=n_parties; i++) { +#ifdef DEBUG + std::cout << "using key: " << left.external_key(i) << endl; +#endif + PRF_chunk(left.external_key(i), gate.input(ext_l, 1), prf_output, PAD_TO_8(n_parties)); + for(party_id_t j=1; j<=n_parties; j++) { + k = *(Key*)(prf_output+16*(j-1)); +#ifdef __PRIME_FIELD__ + k.adjust(); +#endif +#ifdef DEBUG + printf("Fk^%d_{%u,%d}(%d,%u,%d) = ",i, w_l, sig_l,ext_l,g,j); + std::cout << k << std::endl; +#endif + garbled_entry[j-1] -= k; + } + +#ifdef DEBUG + std::cout << "using key: " << right.external_key(i) << endl; +#endif + PRF_chunk(right.external_key(i), gate.input(ext_r, 1) , prf_output, PAD_TO_8(n_parties)); + for(party_id_t j=1; j<=n_parties; j++) { + k = *(Key*)(prf_output+16*(j-1)); +#ifdef __PRIME_FIELD__ + k.adjust(); +#endif +#ifdef DEBUG + printf("Fk^%d_{%u,%d}(%d,%u,%d) = ",i, w_r, sig_r,ext_r,g,j); + std::cout << k << std::endl; +#endif + garbled_entry[j-1] -= k; + } + } + +#if __PURE_SHE__ + for(party_id_t j=1; j<=n_parties; j++) { + garbled_entry[j-1].sqr_in_place(tmp_mpz); + } +#endif + +// for(party_id_t i=1; i<=n_parties; i++) { +// std::cout << garbled_entry[i-1] << " "; +// } +// std::cout << std::endl; + +#ifdef KEY_SIGNAL + external = garbled_entry[my_id - 1].get_signal(); +#else + if(garbled_entry[my_id-1] == key(my_id, 0)) { + external = 0; + } else if (garbled_entry[my_id-1] == key(my_id, 1)) { + external = 1; + } else { + printf("\nERROR!!!\n"); + cout << "got key: " << garbled_entry[my_id - 1] << endl; + cout << "possibilities: " << key(my_id, 0) << " " << key(my_id, 1) << endl; + throw std::invalid_argument("result key doesn't fit any of my keys"); +// return NO_SIGNAL; + } +#endif + +#ifdef DEBUG + std::cout << "k^"<& prf_outputs, SendBuffer& buffer) +{ + (void)func; + (void)gate; + (void)g; + size_t n_parties = CommonParty::singleton->get_n_parties(); + GarbledGate garbled_gate(n_parties); + garbled_gate.reset(); + KeyVector& gg_A = garbled_gate[0]; + KeyVector& gg_B = garbled_gate[1]; + KeyVector& gg_C = garbled_gate[2]; + KeyVector& gg_D = garbled_gate[3]; + + for(party_id_t i=1; i<=n_parties; i++) { +#ifdef DEBUG + std::cout << "adding prfs of party " << i << std::endl ; +#endif + Key left_i_j, right_i_j; + for (party_id_t j=1; j<=n_parties; j++) { + PRFTuple party_prfs; + prf_outputs[i - 1].unserialize(party_prfs); + //A + left_i_j = *(Key*)party_prfs.outputs[0][0][0]; + right_i_j = *(Key*)party_prfs.outputs[1][0][0]; +#ifdef DEBUG + std::cout << "A" << std::endl; + cout << gg_A[j-1] << std::endl; + cout << left_i_j << std::endl; + cout << right_i_j << std::endl; +#endif + gg_A[j-1] += left_i_j; //left wire of party i in part j + gg_A[j-1] += right_i_j; //right wire of party i in part j +// cout << gg_A[j-1] << std::endl<< std::endl; + + //B + left_i_j = *(Key*)party_prfs.outputs[0][0][1]; + right_i_j = *(Key*)party_prfs.outputs[1][1][0]; +#ifdef DEBUG + std::cout << "B" << std::endl; + cout << gg_B[j-1] << std::endl; + cout << left_i_j << std::endl; + cout << right_i_j << std::endl; +#endif + gg_B[j-1] += left_i_j; //left wire of party i in part j + gg_B[j-1] += right_i_j; //right wire of party i in part j +// cout << gg_B[j-1] << std::endl<< std::endl; + + //C + left_i_j = *(Key*)party_prfs.outputs[0][1][0]; + right_i_j = *(Key*)party_prfs.outputs[1][0][1]; +#ifdef DEBUG + std::cout << "C" << std::endl; + cout << gg_C[j-1] << std::endl; + cout << left_i_j << std::endl; + cout << right_i_j << std::endl; +#endif + gg_C[j-1] += left_i_j; //left wire of party i in part j + gg_C[j-1] += right_i_j; //right wire of party i in part j +// cout << gg_C[j-1] << std::endl<< std::endl; + + //D + left_i_j = *(Key*)party_prfs.outputs[0][1][1]; + right_i_j = *(Key*)party_prfs.outputs[1][1][1]; +#ifdef DEBUG + std::cout << "D" << std::endl; + cout << gg_D[j-1] << std::endl; + cout << left_i_j << std::endl; + cout << right_i_j << std::endl; +#endif + gg_D[j-1] += left_i_j; //left wire of party i in part j + gg_D[j-1] += right_i_j; //right wire of party i in part j +// cout << gg_D[j-1] << std::endl<< std::endl; + } + } + + //Adding the hidden keys + left.check_mask(); + right.check_mask(); + check_mask(); + char maskl = left.mask; + char maskr = right.mask; + char masko = mask; +#ifdef DEBUG + printf("\ngate %u, leftwire=%u, rightwire=%u, outwire=%u: func=%d%d%d%d, msk_l=%d, msk_r=%d, msk_o=%d\n" + , g,gate->_left, gate->_right, gate->_out + ,func[0],func[1],func[2],func[3], maskl, maskr, masko); +#endif + +// printf("\n"); +// printf("maskl=%d, maskr=%d, masko=%d\n",maskl,maskr,masko); +// printf("gate func = %d%d%d%d\n",gate->_func[0],gate->_func[1],gate->_func[2],gate->_func[3]); + bool xa = func[2*maskl+maskr] != masko; + bool xb = func[2*maskl+(1-maskr)] != masko; + bool xc = func[2*(1-maskl)+maskr] != masko; + bool xd = func[2*(1-maskl)+(1-maskr)] != masko; + +#ifdef DEBUG + printf("xa=%d, xb=%d, xc=%d, xd=%d\n", xa,xb,xc,xd); +#endif + + // these are the 0-keys +#ifdef __PURE_SHE__ + Key* outwire_start = _circuit->_sqr_keys + gate->_out*2*n_parties; +#else + Register& outwire = *this; +#endif + keys.init(n_parties); + KeyVector& keyxa = outwire[xa]; + KeyVector& keyxb = outwire[xb]; + KeyVector& keyxc = outwire[xc]; + KeyVector& keyxd = outwire[xd]; + + for(party_id_t i=1; i<=n_parties; i++) { +#ifdef DEBUG + std::cout << "adding to A = " << keyxa[i-1] << std::endl; + std::cout << "adding to B = " << keyxb[i-1] << std::endl; + std::cout << "adding to C = " << keyxc[i-1] << std::endl; + std::cout << "adding to D = " << keyxd[i-1] << std::endl; +#endif + gg_A[i-1] += keyxa[i-1]; + gg_B[i-1] += keyxb[i-1]; + gg_C[i-1] += keyxc[i-1]; + gg_D[i-1] += keyxd[i-1]; + } + garbled_gate.serialize_no_allocate(buffer); +#ifdef DEBUG + garbled_gate.print(); +#endif +} + +void PRFRegister::output() +{ + ProgramParty& party = *ProgramParty::singleton; + party.store_wire(*this); +} + +void PRFRegister::op(const ProgramRegister& left, const ProgramRegister& right, Function func) +{ + (void)func; +#ifdef DEBUG + cout << "prf op " << &left << " " << &right << endl; + cout << "sizes " << left.keys[0].size() << " " << right.keys[0].size() << endl; +#endif + const Register* in_wires[2] = { &left, &right }; + ProgramParty& party = *ProgramParty::singleton; + party.receive_keys(*this); + GarbledGate gate(party.get_n_parties()); + gate.compute_prfs_outputs(in_wires, party._id, party.buffers[TYPE_PRF_OUTPUTS], party.new_gate()); +#ifdef DEBUG_FREE_XOR + int i = ProgramParty::s()._id - 1; + Key delta = party.get_delta(); + if (delta != (left.keys[0][i] ^ left.keys[1][i])) + throw runtime_error("inconsistent delta"); + if (delta != (right.keys[0][i] ^ right.keys[1][i])) + throw runtime_error("inconsistent delta"); + if (delta != (keys[0][i] ^ keys[1][i])) + throw runtime_error("inconsistent delta"); +#endif +} + +void PRFRegister::input(party_id_t from, char value) +{ + (void)value; + ProgramParty& party = *ProgramParty::singleton; + party.receive_keys(*this); + party.input(*this, from); +#ifdef DEBUG + cout << "(PRF) input from " << from << ":" << endl; + keys.print(get_id()); +#endif +} + +void PRFRegister::public_input(bool value) +{ + ProgramParty& party = ProgramParty::s(); + int i = party.get_id() - 1; + keys[value][i] = 0; + keys[1 - value][i] = party.get_delta(); + set_mask(0); +} + +void PRFRegister::random() +{ + ProgramParty& party = ProgramParty::s(); + ProgramParty::s().receive_keys(*this); + ProgramParty::s().receive_all_keys(*this, 0); + party.store_wire(*this); + keys[0].serialize(party.wires); +#ifdef DEBUG + cout << "(PRF) random:" << endl; + keys.print(get_id()); +#endif +} + +void EvalRegister::input(party_id_t from, char value) +{ + ProgramParty::s().input_value(from, value); +#ifdef DEBUG + cout << "(Input) input from " << from << ":" << endl; + keys.print(get_id()); +#endif +} + +void EvalRegister::public_input(bool value) +{ + ProgramParty& party = ProgramParty::s(); + set_mask(0); + set_external(value); + for (int i = 0; i < party.get_n_parties(); i++) + set_external_key(i + 1, 0); +} + +void EvalRegister::random() +{ + auto& party = ProgramParty::s(); + party.load_wire(*this); + keys[0].unserialize(party.wires, party.get_n_parties()); + set_external(0); +} + +void RandomRegister::randomize() +{ + TrustedProgramParty& party = *TrustedProgramParty::singleton; + party.random_timer.start(); + init(party.randomfd, party._N); + party.random_timer.stop(); +#ifdef FREE_XOR + keys[1] = keys[0] ^ party.get_deltas(); +#endif + party.add_keys(*this); +} + +void RandomRegister::op(const Register& left, const Register& right, + Function func) +{ + (void)left; + (void)right; + (void)func; + randomize(); + TrustedProgramParty& party = *TrustedProgramParty::singleton; + party.new_gate(); + party.store_wire(*this); +} + +void RandomRegister::input(party_id_t from, char value) +{ + (void)value; + randomize(); +#ifdef DEBUG + cout << "(Random) input from " << from << ":" << endl; + keys.print(get_id()); +#endif + CommonParty::singleton->input(*this, from); +} + +void RandomRegister::public_input(bool value) +{ + auto& party = TrustedProgramParty::s(); + keys.init(party.get_n_parties()); + for (int i = 0; i < party.get_n_parties(); i++) + { + keys[value][i] = 0; + keys[1 - value][i] = party.delta(i); + } + set_mask(0); + party.store_wire(*this); +} + +void GarbleRegister::public_input(bool value) +{ + (void)value; + TrustedProgramParty::s().load_wire(*this); +} + +void RandomRegister::random() +{ + randomize(); + TrustedProgramParty::s().add_all_keys(*this, 0); + TrustedProgramParty::s().store_wire(*this); +#ifdef DEBUG + cout << "random mask: " << get_mask() << endl; + cout << "(Random) random:" << endl; + keys.print(get_id()); +#endif +} + +void GarbleRegister::random() +{ + TrustedProgramParty::s().load_wire(*this); +} + +void RandomRegister::output() +{ + TrustedProgramParty::s().msg_output_masks.push_back(get_mask()); +} + +void EvalRegister::output() +{ + ProgramParty& party = ProgramParty::s(); + party.load_wire(*this); + set_mask(party.output_masks.pop_front()); +#ifdef KEY_SIGNAL +#ifdef DEBUG_REGS + cout << "check " << get_id() << endl; +#endif + check_signal_key(party.get_id(), garbled_entry); +#endif +} + +#ifdef FREE_XOR +void RandomRegister::XOR(const Register& left, const Register& right) +{ + mask = left.get_mask() ^ right.get_mask(); + keys[0] = left.keys[0] ^ right.keys[0]; + keys[1] = keys[0] ^ TrustedProgramParty::singleton->get_deltas(); +} + +void GarbleRegister::XOR(const Register& left, const Register& right) +{ + mask = left.get_mask() ^ right.get_mask(); +} + +void PRFRegister::XOR(const Register& left, const Register& right) +{ + int i = ProgramParty::s()._id - 1; + Key delta = ProgramParty::s().get_delta(); + keys[0][i] = left.keys[0][i] ^ right.keys[0][i]; + keys[1][i] = keys[0][i] ^ delta; +#ifdef DEBUG + cout << "PRF XOR" << endl; + cout << "delta " << delta << endl; + cout << endl; + cout << "res" << endl; + keys.print(get_id()); + cout << "left" << endl; + left.keys.print(left.get_id()); + cout << "right" << endl; + right.keys.print(right.get_id()); +#endif +#ifdef DEBUG_FREE_XOR + if (delta != (left.keys[0][i] ^ left.keys[1][i])) + throw runtime_error("inconsistent delta"); + if (delta != (right.keys[0][i] ^ right.keys[1][i])) + throw runtime_error("inconsistent delta"); + if (delta != (keys[0][i] ^ keys[1][i])) + throw runtime_error("inconsistent delta"); +#endif +} + +void EvalRegister::XOR(const Register& left, const Register& right) +{ + external = left.get_external() ^ right.get_external(); + garbled_entry = left.get_garbled_entry() ^ right.get_garbled_entry(); +#ifdef DEBUG + cout << "Eval XOR *" << get_id() << " = *" << left.get_id() << " ^ *" << right.get_id() << endl; + for (int i = 0; i < garbled_entry.size(); i++) + cout << garbled_entry[i] << " = " << left.get_garbled_entry()[i] + << " ^ " << right.get_garbled_entry()[i] << endl; +#endif +} +#endif + +void EvalRegister::check(const int128& value, word share, int128 mac) +{ +#ifdef DEBUG_DYNAMIC + cout << "check result " << value << endl; +#endif + if (value != 0) + { + cout << "MAC check: " << value << " " << share<< " " << mac << endl; + throw runtime_error("MAC check failed"); + } +} + +void EvalRegister::get_dyn_mask(GC::Mask& mask, int length, int mac_length) +{ + mask.share = CommonParty::s().prng.get_word() & ((1ULL << length) - 1); + mask.mac = int128(CommonParty::s().prng.get_doubleword()) + & int128::ones(mac_length); +#ifdef DEBUG_DYNAMIC + cout << "mask " << hex << mask.share << " " << mask.mac << " "; + cout << ((1ULL << length) - 1) << " " << int128::ones(mac_length) << endl; +#endif +} + +void EvalRegister::unmask(GC::AuthValue& dest, word mask_share, int128 mac_mask_share, + word masked, int128 masked_mac) +{ + dest.share = mask_share; + dest.mac = mac_mask_share; + if (ProgramParty::s()._id == 1) + { + dest.share ^= masked; + dest.mac ^= masked_mac; + } +#ifdef DEBUG_DYNAMIC + cout << dest.share << " ?= " << mask_share << " ^ " << masked << endl; + cout << dest.mac << " ?= " << mac_mask_share << " ^ " << masked_mac << endl; +#endif +} + +template +void EvalRegister::store_clear_in_dynamic(GC::Memory& mem, + const vector& accesses) +{ + for (auto access : accesses) + { + T& dest = mem[access.address]; + GC::Clear value = access.value; + ProgramParty& party = ProgramParty::s(); + dest.assign(value.get(), party.get_mac_key().get(), party.get_id() == 1); +#ifdef DEBUG_DYNAMIC + cout << "store clear " << dest.share << " " << dest.mac << " " << value << endl; +#endif + } +} + +template <> +void RandomRegister::store(GC::Memory& mem, + const vector< GC::WriteAccess< GC::Secret > >& accesses) +{ + (void)mem; + for (auto access : accesses) + { + for (auto& reg : access.source.get_regs()) + TrustedProgramParty::s().store_spdz_wire(SPDZ_STORE, reg); + } +} + +template +void check_for_doubles(const vector& accesses, const char* name) +{ + (void)accesses; + (void)name; +#ifdef OUTPUT_DOUBLES + set seen; + int doubles = 0; + for (auto access : accesses) + { + if (seen.find(access.address) != seen.end()) + doubles++; + seen.insert(access.address); + } + cout << doubles << "/" << accesses.size() << " doubles in " << name << endl; +#endif +} + +template<> +void EvalRegister::store(GC::Memory& mem, + const vector< GC::WriteAccess< GC::Secret > >& accesses) +{ + check_for_doubles(accesses, "storing"); + ProgramParty& party = ProgramParty::s(); + vector< Share > S, S2, S3, S4, S5, SS; + vector exts; + int n_registers = 0; + for (auto access : accesses) + n_registers += access.source.get_regs().size(); + for (auto access : accesses) + { + GC::SpdzShare& dest = mem[access.address]; + dest.assign_zero(); + const vector& sources = access.source.get_regs(); + for (unsigned int i = 0; i < sources.size(); i++) + { + SpdzWire spdz_wire; + party.get_spdz_wire(SPDZ_STORE, spdz_wire); + const Register& reg = sources[i]; + Share tmp; + gf2n ext = (int)reg.get_external(); + //cout << "ext:" << ext << "/" << (int)reg.get_external() << " " << endl; + tmp.add(spdz_wire.mask, ext, party.get_id() == 1, party.get_mac_key()); + S.push_back(tmp); + tmp *= gf2n(1) << i; + dest += tmp; + const Key& key = reg.external_key(party.get_id()); + Key& expected_key = spdz_wire.my_keys[(int)reg.get_external()]; + if (expected_key != key) + { + cout << "wire label: " << key << ", expected: " + << expected_key << endl; + cout << "opposite: " << spdz_wire.my_keys[1-reg.get_external()] << endl; + sources[i].keys.print(sources[i].get_id()); + throw runtime_error("key check failed"); + } +#ifdef DEBUG_SPDZ + S3.push_back(spdz_wire.mask); + S4.push_back(dest); + S5.push_back(tmp); + exts.push_back(ext); +#endif + } +#ifdef DEBUG_SPDZ + SS.push_back(dest); +#endif + } + +#ifdef DEBUG_SPDZ + party.MC->Check(*party.P); + vector v, v3, vv; + party.MC->POpen_Begin(vv, SS, *party.P); + party.MC->POpen_End(vv, SS, *party.P); + cout << "stored " << vv.back() << " from bits:"; + vv.pop_back(); + party.MC->Check(*party.P); + party.MC->POpen_Begin(v, S, *party.P); + party.MC->POpen_End(v, S, *party.P); + for (auto val : v) + cout << val.get_bit(0); + party.MC->Check(*party.P); + cout << " / exts:"; + for (auto ext : exts) + cout << ext.get_bit(0); + cout << " / masks:"; + party.MC->POpen_Begin(v3, S3, *party.P); + party.MC->POpen_End(v3, S3, *party.P); + for (auto val : v3) + cout << val.get_word(); + cout << endl; + party.MC->Check(*party.P); + cout << "share: " << SS.back() << endl; + party.MC->Check(*party.P); + + party.MC->POpen_Begin(v, S4, *party.P); + party.MC->POpen_End(v, S4, *party.P); + for (auto x : v) + cout << x << " "; + cout << endl; + + party.MC->POpen_Begin(v, S5, *party.P); + party.MC->POpen_End(v, S5, *party.P); + for (auto x : v) + cout << x << " "; + cout << endl; + + party.MC->POpen_Begin(v, S2, *party.P); + party.MC->POpen_End(v, S2, *party.P); + party.MC->Check(*party.P); +#endif +} + +template <> +void RandomRegister::load(vector > >& accesses, + const GC::Memory& source) +{ + (void)source; + for (auto access : accesses) + for (auto& reg : access.dest.get_regs()) + { + ((RandomRegister*)®)->randomize(); + TrustedProgramParty::s().store_spdz_wire(SPDZ_LOAD, reg); + TrustedProgramParty::s().store_wire(reg); + } +} + +template <> +void GarbleRegister::load(vector > >& accesses, + const GC::Memory& source) +{ + (void)source; + for (auto access : accesses) + for (auto& reg : access.dest.get_regs()) + TrustedProgramParty::s().load_wire(reg); +} + +template <> +void PRFRegister::load(vector > >& accesses, + const GC::Memory& source) +{ + (void)source; + for (auto access : accesses) + for (auto& reg : access.dest.get_regs()) + { + ProgramParty::s().receive_keys(reg); + ProgramParty::s().store_wire(reg); + } +} + +template <> +void EvalRegister::load(vector > >& accesses, + const GC::Memory& mem) +{ + check_for_doubles(accesses, "loading"); + vector< Share > shares; + shares.reserve(accesses.size()); + ProgramParty& party = ProgramParty::s(); + deque spdz_wires; + vector< Share > S; + for (auto access : accesses) + { + const GC::SpdzShare& source = mem[access.address]; + Share mask; + vector& dests = access.dest.get_regs(); + for (unsigned int i = 0; i < dests.size(); i++) + { + spdz_wires.push_back({}); + ProgramParty::s().get_spdz_wire(SPDZ_LOAD, spdz_wires.back()); + mask += spdz_wires.back().mask << i; + } + shares.push_back(source + mask); +#ifdef DEBUG_SPDZ + S.push_back(source); +#endif + } + +#ifdef DEBUG_SPDZ + party.MC->Check(*party.P); + vector v; + party.MC->POpen_Begin(v, S, *party.P); + party.MC->POpen_End(v, S, *party.P); + for (size_t j = 0; j < accesses.size(); j++) + { + cout << "loaded " << v[j] << " / "; + vector& dests = accesses[j].dest.get_regs(); + for (unsigned int i = 0; i < dests.size(); i++) + cout << (int)dests[i].get_external(); + cout << " from " << S[j] << endl; + } + party.MC->Check(*party.P); +#endif + + vector masked; + party.MC->POpen_Begin(masked, shares, *party.P); + party.MC->POpen_End(masked, shares, *party.P); + vector keys(party.get_n_parties()); + + for (size_t j = 0; j < accesses.size(); j++) + { + vector& dests = accesses[j].dest.get_regs(); + for (unsigned int i = 0; i < dests.size(); i++) + { + bool ext = masked[j].get_bit(i); + party.load_wire(dests[i]); + dests[i].set_external(ext); + keys[party.get_id() - 1].serialize(spdz_wires.front().my_keys[ext]); + spdz_wires.pop_front(); + } + } + + party.P->Broadcast_Receive(keys, true); + + int base = 0; + for (auto access : accesses) + { + vector& dests = access.dest.get_regs(); + for (unsigned int i = 0; i < dests.size(); i++) + for (int j = 0; j < party.get_n_parties(); j++) + { + Key key; + keys[j].unserialize(key); + dests[i].set_external_key(j + 1, key); + } + base += dests.size() * party.get_n_parties(); + } + +#ifdef DEBUG_SPDZ + cout << "masked: "; + for (auto& m : masked) + cout << m << " "; + cout << endl; +#endif +} + +void KeyVector::operator=(const KeyVector& other) +{ + resize(other.size()); + avx_memcpy(data(), other.data(), byte_size()); +} + +KeyVector KeyVector::operator^(const KeyVector& other) const +{ + if (size() != other.size()) + throw runtime_error("size mismatch"); + KeyVector res; + res.resize(size()); + for (size_t i = 0; i < size(); i++) + res[i] = (*this)[i] ^ other[i]; + return res; +} + +ostream& operator<<(ostream& os, const KeyVector& kv) +{ + for (size_t i = 0; i < kv.size(); i++) + os << kv[i] << " "; + return os; +} + +template +KeyTuple KeyTuple::operator^(const KeyTuple& other) const +{ + KeyTuple res; + for (int i = 0; i < I; i++) + res[i] = (*this)[i] ^ other[i]; + return res; +} + +template +void KeyTuple::copy_to(Key* dest) { + for (int b = 0; b < I; b++) + avx_memcpy(dest + b * keys[0].size(), keys[b].data(), part_size()); +} + +template +void KeyTuple::copy_from(Key* source, int n_parties, int except) +{ +#ifdef DEBUG + cout << "skip copying for " << except << endl; +#endif + for (int b = 0; b < I; b++) + { + keys[b].resize(n_parties); + for (int i = 0; i < n_parties; i++) + { + if (i != except) + keys[b][i] = *source; + source++; +#ifdef DEBUG + cout << "copy from " << b << " " << i << " " << keys[b][i] << endl; +#endif + } + } +} + +template +long KeyTuple::counter = 0; + +template +void KeyTuple::randomize() +{ + for (int i = 0; i < I; i++) + { + CommonParty::s().prng.get_octets((octet*)keys[i].data(), part_size()); +#ifdef DEBUG + for (int j = 0; j < keys[i].size(); j++) + { + keys[i][j] = { 0, (counter << 16) + (i << 8) + j }; + counter++; + } +#endif +#ifdef __PRIME_FIELD__ + for (int j = 0; j < keys[i].size(); j++) + { + keys[i][j].adjust(); + } +#endif + } +} + +template +void KeyTuple::print(int wire_id) const +{ + for(int b=0; b +void KeyTuple::print(int wire_id, party_id_t pid) +{ + for(int b=0; b; +template class KeyTuple<4>; + +template void EvalRegister::store_clear_in_dynamic( + GC::Memory& mem, const vector& accesses); +template void EvalRegister::store_clear_in_dynamic( + GC::Memory& mem, const vector& accesses); diff --git a/BMR/Register.h b/BMR/Register.h new file mode 100644 index 00000000..fb0e3ee2 --- /dev/null +++ b/BMR/Register.h @@ -0,0 +1,394 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Register.h + * + */ + +#ifndef PROTOCOL_SRC_REGISTER_H_ +#define PROTOCOL_SRC_REGISTER_H_ + +#include +#include +#include +using namespace std; + +#include "Key.h" +#include "Wire.h" +#include "GC/Clear.h" +#include "GC/Memory.h" +#include "GC/Access.h" +#include "Math/gf2n.h" +#include "Tools/FlexBuffer.h" + +#ifndef FREE_XOR +#warning not using free XOR has not been tested in a while +#endif + +typedef unsigned int party_id_t; + +//#define PAD_TO_8(n) (n+8-n%8) +#define PAD_TO_8(n) (n) + +#ifdef N_PARTIES +#define MAX_N_PARTIES N_PARTIES +#endif + +#ifdef MAX_N_PARTIES +class BaseKeyVector +{ + Key keys[MAX_N_PARTIES]; +public: + Key& operator[](int i) { return keys[i]; } + const Key& operator[](int i) const { return keys[i]; } + Key* data() { return keys; } + const Key* data() const { return keys; } +#ifdef N_PARTIES + BaseKeyVector(int n_parties = 0) { (void)n_parties; avx_memzero(keys, sizeof(keys)); } + size_t size() const { return N_PARTIES; } + void resize(int size) { (void)size; } +#else + BaseKeyVector(int n_parties = 0) : n_parties(n_parties) { memset(keys, 0, sizeof(keys)); } + size_t size() const { return n_parties; } + void resize(int size) { n_parties = size; } +private: + int n_parties; +#endif +}; +#else +typedef vector BaseKeyVector; +#endif + +class KeyVector : public BaseKeyVector +{ +public: + KeyVector(int size = 0) : BaseKeyVector(size) {} + size_t byte_size() const { return size() * sizeof(Key); } + void operator=(const KeyVector& source); + KeyVector operator^(const KeyVector& other) const; + template + void serialize_no_allocate(T& output) const { output.serialize_no_allocate(data(), byte_size()); } + template + void serialize(T& output) const { output.serialize(data(), byte_size()); } + void unserialize(ReceivedMsg& source, int n_parties); + friend ostream& operator<<(ostream& os, const KeyVector& kv); +}; + +class GarbledGate; +class CommonParty; + +template +class KeyTuple { + friend class Register; + + static long counter; + +protected: + KeyVector keys[I]; + + int part_size() { return keys[0].size() * sizeof(Key); } +public: + KeyTuple() {} + KeyTuple(int n_parties) { init(n_parties); } + void init(int n_parties); + int byte_size() { return I * keys[0].byte_size(); } + KeyVector& operator[](int i) { return keys[i]; } + const KeyVector& operator[](int i) const { return keys[i]; } + KeyTuple operator^(const KeyTuple& other) const; + void copy_to(Key* dest); + void unserialize(ReceivedMsg& source, int n_parties); + void copy_from(Key* source, int n_parties, int except); + template + void serialize_no_allocate(T& output) const; + template + void serialize(T& output) const; + template + void serialize(T& output, party_id_t pid) const; + void unserialize(vector& output); + template + void unserialize(T& output); + void randomize(); + void reset(); + void print(int wire_id) const; + void print(int wire_id, party_id_t pid); +}; + +namespace GC +{ +class AuthValue; +class Mask; +class SpdzShare; +template +class Secret; +} + +class Register { +protected: + static int counter; + + KeyVector garbled_entry; + char external; + +public: + char mask; + KeyTuple<2> keys; /* Additional data stored per per party per wire: */ + /* Total of n*W*2 keys + * For every w={0,...,W} + * For every b={0,1} + * For every i={1...n} + * k^i_{w,b} + * This is helpful that the keys for specific w and b are adjacent + * for pipelining matters. + */ + + Register(int n_parties); + + void init(int n_parties); + void init(int rfd, int n_parties); + KeyVector& operator[](int i) { return keys[i]; } + const Key& key(party_id_t i, int b) const { return keys[b][i-1]; } + Key& key(party_id_t i, int b) { return keys[b][i-1]; } + void set_eval_keys(); + void set_eval_keys(Key* keys, int n_parties, int except); + const Key& external_key(party_id_t i) const { return garbled_entry[i-1]; } + void set_external_key(party_id_t i, const Key& key); + void reset_non_external_key(party_id_t i); + void set_external(char ext); + char get_external() const { check_external(); return external; } + char get_external_no_check() const { return external; } + void set_mask(char mask); + int get_mask() const { check_mask(); return mask; } + char get_mask_no_check() { return mask; } + char get_output() { check_external(); check_mask(); return mask ^ external; } + char get_output_no_check() { return mask ^ external; } + const KeyVector& get_garbled_entry() const { return garbled_entry; } + void print_input(int id); + void print() const { keys.print(get_id()); } + void check_external() const; + void check_mask() const; + void check_signal_key(int my_id, KeyVector& garbled_entry); + + void eval(const Register& left, const Register& right, GarbledGate& gate, + party_id_t my_id, char* prf_output, int, int, int); + + void garble(const Register& left, const Register& right, Function func, + Gate* gate, int g, vector& prf_outputs, SendBuffer& buffer); + + size_t get_id() const { return (size_t)this; } + + template + void set_trace(); +}; + + +// this is to fake a "cout" that does nothing +class BlackHole +{ +public: + template + BlackHole& operator<<(T) { return *this; } + BlackHole& operator<<(BlackHole& (*__pf)(BlackHole&)) { (void)__pf; return *this; } +}; +inline BlackHole& endl(BlackHole& b) { return b; } +inline BlackHole& flush(BlackHole& b) { return b; } + +class ProgramRegister : public Register +{ +public: + typedef BlackHole out_type; + static const BlackHole out; + + static Register new_reg(); + static Register tmp_reg() { return new_reg(); } + static Register and_reg() { return new_reg(); } + + static void check(const int128& value, word share, int128 mac) + { (void)value; (void)share; (void)mac; } + static void get_dyn_mask(GC::Mask& mask, int length, int mac_length) + { (void)mask; (void)length; (void)mac_length; } + template + static void store_clear_in_dynamic(T& mem, const vector& accesses) + { (void)mem; (void)accesses; } + static void unmask(GC::AuthValue& dest, word mask_share, int128 mac_mask_share, + word masked, int128 masked_mac) + { (void)dest; (void)mask_share; (void)mac_mask_share; (void)masked; (void)masked_mac; } + + template + static void store(GC::Memory& dest, + const vector >& accesses) { (void)dest; (void)accesses; } + template + static void load(vector >& accesses, + const GC::Memory& source) { (void)accesses; (void)source; } + + template + static void andrs(T& processor, const vector& args) { processor.andrs(args); } + + void input(party_id_t from, char value = -1) { (void)from; (void)value; } + void public_input(bool value) { (void)value; } + void random() {} + char get_output() { return 0; } +}; + +class FirstRoundRegister : public ProgramRegister +{ +public: +}; + +class SecondRoundRegister : public ProgramRegister +{ +public: +}; + +class PRFRegister : public FirstRoundRegister +{ +public: + static string name() { return "PRF"; } + + template + static void load(vector >& accesses, + const GC::Memory& source); + + void op(const ProgramRegister& left, const ProgramRegister& right, Function func); + void XOR(const Register& left, const Register& right); + void input(party_id_t from, char input = -1); + void public_input(bool value); + void random(); + void output(); +}; + +class EvalRegister : public SecondRoundRegister +{ +public: + static string name() { return "Evaluation"; } + + typedef ostream& out_type; + static ostream& out; + + static void check(const int128& value, word share, int128 mac); + static void get_dyn_mask(GC::Mask& mask, int length, int mac_length); + static void unmask(GC::AuthValue& dest, word mask_share, int128 mac_mask_share, + word masked, int128 masked_mac); + + template + static void store(GC::Memory& dest, + const vector >& accesses); + template + static void load(vector >& accesses, + const GC::Memory& source); + + template + static void andrs(T& processor, const vector& args); + + void op(const ProgramRegister& left, const ProgramRegister& right, Function func); + void XOR(const Register& left, const Register& right); + + void public_input(bool value); + void random(); + void output(); + unsigned long long get_output() { return Register::get_output(); } + + template + static void store_clear_in_dynamic(GC::Memory& mem, + const vector& accesses); + void input(party_id_t from, char value = -1); +}; + +class GarbleRegister : public SecondRoundRegister +{ +public: + static string name() { return "Garbling"; } + + template + static void load(vector >& accesses, + const GC::Memory& source); + + void op(const Register& left, const Register& right, Function func); + void XOR(const Register& left, const Register& right); + void public_input(bool value); + void random(); + void output() {} +}; + +class RandomRegister : public FirstRoundRegister +{ +public: + static string name() { return "Randomization"; } + + template + static void store(GC::Memory& dest, + const vector >& accesses); + template + static void load(vector >& accesses, + const GC::Memory& source); + + void randomize(); + + void op(const Register& left, const Register& right, Function func); + void XOR(const Register& left, const Register& right); + + void input(party_id_t from, char value = -1); + void public_input(bool value); + void random(); + void output(); +}; + + +inline Register::Register(int n_parties) : + garbled_entry(n_parties), external(NO_SIGNAL), + mask(NO_SIGNAL), keys(n_parties) +{ +} + +inline void KeyVector::unserialize(ReceivedMsg& source, int n_parties) +{ + resize(n_parties); + source.unserialize(data(), size() * sizeof(Key)); +} + +template +inline void KeyTuple::init(int n_parties) { + for (int i = 0; i < I; i++) + keys[i].resize(n_parties); +} + +template +inline void KeyTuple::reset() +{ + for (int i = 0; i < I; i++) + for (size_t j = 0; j < keys[i].size(); j++) + keys[i][j] = 0; +} + +template +inline void KeyTuple::unserialize(ReceivedMsg& source, int n_parties) { + for (int b = 0; b < I; b++) + keys[b].unserialize(source, n_parties); +} + +template template +void KeyTuple::serialize_no_allocate(T& output) const { + for (int i = 0; i < I; i++) + keys[i].serialize_no_allocate(output); +} + +template template +void KeyTuple::serialize(T& output) const { + for (int i = 0; i < I; i++) + for (unsigned int j = 0; j < keys[i].size(); j++) + keys[i][j].serialize(output); +} + +template template +void KeyTuple::serialize(T& output, party_id_t pid) const { + for (int i = 0; i < I; i++) + keys[i][pid - 1].serialize(output); +} + +template template +void KeyTuple::unserialize(T& output) { + for (int i = 0; i < I; i++) + for (unsigned int j = 0; j < keys[i].size(); j++) + output.unserialize(keys[i][j]); +} + +#endif /* PROTOCOL_SRC_REGISTER_H_ */ diff --git a/BMR/Register_inline.h b/BMR/Register_inline.h new file mode 100644 index 00000000..8f98e3ac --- /dev/null +++ b/BMR/Register_inline.h @@ -0,0 +1,20 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Register_inline.h + * + */ + +#ifndef BMR_REGISTER_INLINE_H_ +#define BMR_REGISTER_INLINE_H_ + +#include "CommonParty.h" +#include "Party.h" + + +inline Register ProgramRegister::new_reg() +{ + return Register(CommonParty::s().get_n_parties()); +} + +#endif /* BMR_REGISTER_INLINE_H_ */ diff --git a/BMR/SpdzWire.cpp b/BMR/SpdzWire.cpp new file mode 100644 index 00000000..41dcf136 --- /dev/null +++ b/BMR/SpdzWire.cpp @@ -0,0 +1,26 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * SpdzWire.cpp + * + */ + +#include "SpdzWire.h" + +SpdzWire::SpdzWire() +{ + +} + +void SpdzWire::pack(octetStream& os) const +{ + mask.pack(os); + os.serialize(my_keys); +} + +void SpdzWire::unpack(octetStream& os, size_t wanted_size) +{ + (void)wanted_size; + mask.unpack(os); + os.unserialize(my_keys); +} diff --git a/BMR/SpdzWire.h b/BMR/SpdzWire.h new file mode 100644 index 00000000..cb903c6d --- /dev/null +++ b/BMR/SpdzWire.h @@ -0,0 +1,25 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * SpdzWire.h + * + */ + +#ifndef BMR_SPDZWIRE_H_ +#define BMR_SPDZWIRE_H_ + +#include "Math/Share.h" +#include "Key.h" + +class SpdzWire +{ +public: + Share mask; + Key my_keys[2]; + + SpdzWire(); + void pack(octetStream& os) const; + void unpack(octetStream& os, size_t wanted_size); +}; + +#endif /* BMR_SPDZWIRE_H_ */ diff --git a/BMR/TrustedParty.cpp b/BMR/TrustedParty.cpp index 8d3f9a0b..ce3dac92 100644 --- a/BMR/TrustedParty.cpp +++ b/BMR/TrustedParty.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * TrustedParty.cpp * - * Created on: Feb 15, 2016 - * Author: bush */ #include "TrustedParty.h" @@ -16,9 +16,25 @@ #include "proto_utils.h" #include "msg_types.h" +#include "SpdzWire.h" +#include "Auth/fake-stuff.h" + +TrustedProgramParty* TrustedProgramParty::singleton = 0; +BaseTrustedParty::BaseTrustedParty() +{ +#ifdef __PURE_SHE__ + init_modulos(); + init_temp_mpz_t(_temp_mpz); + std::cout << "_temp_mpz: " << _temp_mpz << std::endl; +#endif + _num_prf_received = 0; + _received_gc_received = 0; + n_received = 0; + randomfd = open("/dev/urandom", O_RDONLY); +} TrustedParty::TrustedParty(const char* netmap_file, // required to init Node const char* circuit_file // required to init BooleanCircuit @@ -26,126 +42,231 @@ TrustedParty::TrustedParty(const char* netmap_file, // required to init Node { _circuit = new BooleanCircuit( circuit_file ); _G = _circuit->NumGates(); +#ifndef N_PARTIES _N = _circuit->NumParties(); +#endif _W = _circuit->NumWires(); _OW = _circuit->NumOutWires(); -#ifdef __PURE_SHE__ - init_modulos(); - init_temp_mpz_t(_temp_mpz); - std::cout << "_temp_mpz: " << _temp_mpz << std::endl; -#endif - _allocate_prf_outputs(); - _allocate_garbled_table(); - _num_prf_received = 0; - _received_gc_received = 0; - if (0 == strcmp(netmap_file, LOOPBACK_STR)) { - _node = new Node( NULL, 0, this , _N+1); - } else { - _node = new Node( netmap_file, 0, this ); - } + reset(); + garbled_tbl_size = _G; + init(netmap_file, 0, _N); } +TrustedProgramParty::TrustedProgramParty(int argc, char** argv) : + machine(dynamic_memory), processor(machine), + random_machine(dynamic_memory), random_processor(random_machine) +{ + if (argc < 2) + { + cerr << "Usage: " << argv[0] << " [netmap]" << endl; + exit(1); + } + ifstream file((string("Programs/Bytecode/") + argv[1] + "-0.bc").c_str()); + program.parse(file); + processor.reset(program); + machine.reset(program); + random_processor.reset(program.cast< GC::Secret >()); + random_machine.reset(program.cast< GC::Secret >()); + if (singleton) + throw runtime_error("there can only be one"); + singleton = this; + if (argc == 3) + init(argv[2], 0); + else + init("LOOPBACK", 0); +#ifdef FREE_XOR + deltas.resize(_N); + for (size_t i = 0; i < _N; i++) + { + deltas[i] = prng.get_doubleword(); +#ifdef DEBUG + deltas[i] = Key(i + 1, 0); +#endif +#ifdef KEY_SIGNAL + if (deltas[i].get_signal() == 0) + deltas[i] ^= Key(1); +#endif + cout << "Delta " << i << ": " << deltas[i] << endl; + } +#endif +} + +TrustedProgramParty::~TrustedProgramParty() +{ + cout << "Random timer: " << random_timer.elapsed() << endl; +} TrustedParty::~TrustedParty() { - // TODO Auto-generated destructor stub } -void TrustedParty::NodeReady() +void BaseTrustedParty::NodeReady() { +#ifdef DEBUG_STEPS printf("\n\nNode ready \n\n"); - sleep(1); +#endif + //sleep(1); + prepare_randomness(); + send_randomness(); + prf_outputs.resize(get_n_parties()); +} - _generate_masks(); +void BaseTrustedParty::prepare_randomness() +{ + msg_keys.resize(_N); + for (size_t i = 0; i < msg_keys.size(); i++) + { + msg_keys[i].clear(); + fill_message_type(msg_keys[i], TYPE_KEYS); + msg_keys[i].resize(MSG_KEYS_HEADER_SZ); + } - unsigned int number_of_keys = 2* _W * _N; - unsigned int size_of_keys = number_of_keys*sizeof(Key); - unsigned int msg_keys_size = size_of_keys + MSG_KEYS_HEADER_SZ; - - Key* all_keys = new Key[number_of_keys]; - memset(all_keys, 0, size_of_keys); #ifdef __PURE_SHE__ _circuit->_sqr_keys = new Key[number_of_keys]; memset(_circuit->_sqr_keys, 0, size_of_keys); #endif - for(party_id_t pid=1; pid<=_N; pid++) - { - /* generating and sending keys */ - char* msg_keys = new char[msg_keys_size]; - memset(msg_keys, 0, msg_keys_size); - fill_message_type(msg_keys, TYPE_KEYS); - Key* party_keys = (Key*)(msg_keys + MSG_KEYS_HEADER_SZ); #ifdef __PURE_SHE__ _fill_keys_for_party(_circuit->_sqr_keys, party_keys, pid); #else - _fill_keys_for_party(party_keys, pid); + done_filling = _fill_keys(); #endif -// printf("keys for party %u\n", pid); -// phex(party_keys, size_of_keys); - - _merge_keys(all_keys, party_keys); +} +void BaseTrustedParty::send_randomness() +{ + for(party_id_t pid=1; pid<=_N; pid++) + { // printf("all keys\n"); // phex(all_keys, size_of_keys); - _node->Send(pid, msg_keys, msg_keys_size); - - /* sending masks for input wires */ - party_t party = _circuit->Party(pid); - char* msg_input_masks = new char[sizeof(MSG_TYPE) + party.n_wires]; - fill_message_type(msg_input_masks, TYPE_MASK_INPUTS); - memcpy(msg_input_masks+sizeof(MSG_TYPE), _circuit->Masks()+party.wires, party.n_wires); - _node->Send(pid, msg_input_masks, sizeof(MSG_TYPE) + party.n_wires); - // TODO: test only -// printf("input masks for party %d\n", pid); -// phex(msg_input_masks + sizeof(MSG_TYPE) , party.n_wires); + _node->Send(pid, msg_keys[pid - 1]); +// printf("msg keys\n"); +// phex(msg_keys, msg_keys_size); + send_input_masks(pid); } - _circuit->Keys(all_keys); + send_output_masks(); +} +void TrustedParty::send_input_masks(party_id_t pid) +{ + prepare_input_regs(pid); + /* sending masks for input wires */ + msg_input_masks.resize(get_n_parties()); + SendBuffer& buffer = msg_input_masks[pid-1]; + buffer.clear(); + fill_message_type(buffer, TYPE_MASK_INPUTS); + for (auto input_regs = input_regs_queue.begin(); + input_regs != input_regs_queue.end(); input_regs++) + { + int n_wires = (*input_regs)[pid].size(); +#ifdef DEBUG_ROUNDS + cout << dec << n_wires << " inputs from " << pid << endl; +#endif + for (int i = 0; i < n_wires; i++) + buffer.push_back(registers[(*input_regs)[pid][i]].get_mask()); +#ifdef DEBUG2 + printf("input masks for party %d\n", pid); + phex(buffer); +#endif +#ifdef DEBUG_VALUES + printf("input masks for party %d:\t", pid); + print_masks((*input_regs)[pid]); + cout << "on registers:" << endl; + print_indices((*input_regs)[pid]); +#endif + } +#ifdef DEBUG_ROUNDS + cout << "sending " << dec << buffer.size() - 4 << " input masks" << endl; +#endif + _node->Send(pid, buffer); +} + +void TrustedParty::send_output_masks() +{ + prepare_output_regs(); /* output wires' masks are the same for all players */ /* sending masks for output wires */ - char* msg_output_masks = new char[sizeof(MSG_TYPE) + _OW]; - fill_message_type(msg_output_masks, TYPE_MASK_OUTPUT); - memcpy(msg_output_masks + sizeof(MSG_TYPE), _circuit->Masks()+_circuit->OutWiresStart(), _OW); - _node->Broadcast(msg_output_masks, sizeof(MSG_TYPE) + _OW); - // TODO: test only -// printf("output masks\n"); -// phex(msg_output_masks+ sizeof(MSG_TYPE) , _OW); + int _OW = output_regs.size(); + SendBuffer& msg_output_masks = get_buffer(TYPE_MASK_OUTPUT); + for (int i = 0; i < _OW; i++) + msg_output_masks.push_back(get_reg(output_regs[i]).get_mask()); + _node->Broadcast(msg_output_masks); +#ifdef DEBUG2 + printf("output masks\n"); + phex(msg_output_masks); +#endif +#ifdef DEBUG_VALUES + printf("output masks:\t\t\t"); + print_masks(output_regs); + cout << "on registers:" << endl; + print_indices(output_regs); +#endif } -void TrustedParty::NewMessage(int from, char* message, unsigned int len) +void TrustedProgramParty::send_output_masks() { +#ifdef DEBUG_OUTPUT_MASKS + cout << "sending " << msg_output_masks.size() - 4 << " output masks" << endl; +#endif + _node->Broadcast(msg_output_masks); +} +void BaseTrustedParty::NewMessage(int from, ReceivedMsg& msg) +{ + char* message = msg.data(); + int len = msg.size(); MSG_TYPE message_type; - memcpy(&message_type, message, sizeof(MSG_TYPE)); + msg.unserialize(message_type); + unique_lock locker(global_lock); switch(message_type) { case TYPE_PRF_OUTPUTS: { +#ifdef DEBUG + cout << "TYPE_PRF_OUTPUTS" << endl; +#endif _print_mx.lock(); -// printf("got message of len %u from %d\n", len, from); +#ifdef DEBUG2 + printf("got message of len %u from %d\n", len, from); + phex(message, len); + cout << "garbled table size " << get_garbled_tbl_size() << endl; +#endif +#ifdef DEBUG_STEPS printf("\n Got prfs from %d\n",from); +#endif - char* party_prfs = _circuit->Prfs() + (PRFS_PER_PARTY(_G, _N)*sizeof(Key)) *(from-1) ; - memcpy(party_prfs, message + sizeof(MSG_TYPE), PRFS_PER_PARTY(_G, _N)*sizeof(Key)); -// phex(party_prfs, PRFS_PER_PARTY(G, N)*sizeof(Key)); + prf_outputs[from-1] = msg; _print_mx.unlock(); - _num_prf_received ++; - if(_num_prf_received == _N) { + if(++_num_prf_received == _N) { + _num_prf_received = 0; _compute_send_garbled_circuit(); } break; } case TYPE_RECEIVED_GC: { - _received_gc_received++; - if(_received_gc_received == _N) { - _launch_online(); + if(++_received_gc_received == _N) { + _received_gc_received = 0; + if (done_filling) + _launch_online(); + else + NodeReady(); } break; } + case TYPE_NEXT: + if (++n_received == _N) + { + n_received = 0; + send_randomness(); + } + break; + case TYPE_DONE: + if (++n_received == _N) + _node->Stop(); + break; default: { _print_mx.lock(); @@ -155,6 +276,7 @@ void TrustedParty::NewMessage(int from, char* message, unsigned int len) phex(message, len); _print_mx.unlock(); } + break; } } @@ -163,155 +285,57 @@ void TrustedParty::_launch_online() { printf("press to launch online\n"); getchar(); - char* launch_msg = new char[sizeof(MSG_TYPE)]; - fill_message_type(launch_msg, TYPE_LAUNCH_ONLINE); - _node->Broadcast(launch_msg, sizeof(MSG_TYPE)); + _node->Broadcast(get_buffer(TYPE_LAUNCH_ONLINE)); printf("launched\n"); } -void TrustedParty::_allocate_garbled_table() +void TrustedProgramParty::_launch_online() { - unsigned int garbled_table_sz = _G*4*_N*sizeof(Key)+RESERVE_FOR_MSG_TYPE; - _circuit->_garbled_tbl = (Key*)malloc(garbled_table_sz); - memset(_circuit->_garbled_tbl,0,garbled_table_sz); - + _node->Broadcast(get_buffer(TYPE_LAUNCH_ONLINE)); } -void TrustedParty::_compute_send_garbled_circuit() +void TrustedParty::garble() { - - Key* tbl_start = _circuit->_garbled_tbl+(RESERVE_FOR_MSG_TYPE/sizeof(Key)); - unsigned int prfs_per_party_sz = PRFS_PER_PARTY(_G,_N)*sizeof(Key); - std::vector* gates = &_circuit->_gates; - char* masks = _circuit->_masks; - for(gate_id_t g=1; g<=_G; g++) { -// std::cout << "garbling gate " << g << std::endl ; - Key* gg_A = tbl_start + GARBLED_GATE_SIZE(_N)*(g-1); - Key* gg_B = gg_A + _N; - Key* gg_C = gg_A + 2*_N; - Key* gg_D = gg_A + 3*_N; - unsigned int prfs_left_offset = (g-1)*8*_N*sizeof(Key); - unsigned int prfs_right_offset = prfs_left_offset + 4*_N*sizeof(Key); - - for(party_id_t i=1; i<=_N; i++) { -// std::cout << "adding prfs of party " << i << std::endl ; - char* party_prfs = _circuit->Prfs() + (i-1)*prfs_per_party_sz; - Key left_i_j, right_i_j; - for (party_id_t j=1; j<=_N; j++) { - //A -// std::cout << "A" << std::endl; - left_i_j = *(Key*)(party_prfs+prfs_left_offset + (j-1)*sizeof(Key)); - right_i_j = *(Key*)(party_prfs+prfs_right_offset + (j-1)*sizeof(Key)); -// cout << *(gg_A+j-1) << std::endl; -// cout << left_i_j << std::endl; -// cout << right_i_j << std::endl; - *(gg_A+j-1) += left_i_j; //left wire of party i in part j - *(gg_A+j-1) += right_i_j; //right wire of party i in part j -// cout << *(gg_A+j-1) << std::endl<< std::endl; - - //B -// std::cout << "B" << std::endl; - left_i_j = *(Key*)(party_prfs+prfs_left_offset + _N*sizeof(Key) + (j-1)*sizeof(Key)); - right_i_j = *(Key*)(party_prfs+prfs_right_offset + 2*_N*sizeof(Key) + (j-1)*sizeof(Key)); -// cout << *(gg_B+j-1) << std::endl; -// cout << left_i_j << std::endl; -// cout << right_i_j << std::endl; - *(gg_B+j-1) += left_i_j; //left wire of party i in part j - *(gg_B+j-1) += right_i_j; //right wire of party i in part j -// cout << *(gg_B+j-1) << std::endl<< std::endl; - - //C -// std::cout << "C" << std::endl; - left_i_j = *(Key*)(party_prfs+prfs_left_offset + 2*_N*sizeof(Key) + (j-1)*sizeof(Key)); - right_i_j = *(Key*)(party_prfs+prfs_right_offset + _N*sizeof(Key) + (j-1)*sizeof(Key)); -// cout << *(gg_C+j-1) << std::endl; -// cout << left_i_j << std::endl; -// cout << right_i_j << std::endl; - *(gg_C+j-1) += left_i_j; //left wire of party i in part j - *(gg_C+j-1) += right_i_j; //right wire of party i in part j -// cout << *(gg_C+j-1) << std::endl<< std::endl; - - //D -// std::cout << "D" << std::endl; - left_i_j = *(Key*)(party_prfs+prfs_left_offset + 3*_N*sizeof(Key) + (j-1)*sizeof(Key)); - right_i_j = *(Key*)(party_prfs+prfs_right_offset + 3*_N*sizeof(Key) + (j-1)*sizeof(Key)); -// cout << *(gg_D+j-1) << std::endl; -// cout << left_i_j << std::endl; -// cout << right_i_j << std::endl; - *(gg_D+j-1) += left_i_j; //left wire of party i in part j - *(gg_D+j-1) += right_i_j; //right wire of party i in part j -// cout << *(gg_D+j-1) << std::endl<< std::endl; - } - } - - //Adding the hidden keys - Gate* gate = &gates->at(g); - char maskl = masks[gate->_left]; - char maskr = masks[gate->_right]; - char masko = masks[gate->_out]; -// printf("\ngate %u, leftwire=%u, rightwire=%u, outwire=%u: func=%d%d%d%d, msk_l=%d, msk_r=%d, msk_o=%d\n" -// , g,gate->_left, gate->_right, gate->_out -// ,gate->_func[0],gate->_func[1],gate->_func[2],gate->_func[3], maskl, maskr, masko); - -// printf("\n"); -// printf("maskl=%d, maskr=%d, masko=%d\n",maskl,maskr,masko); -// printf("gate func = %d%d%d%d\n",gate->_func[0],gate->_func[1],gate->_func[2],gate->_func[3]); - bool xa = gate->_func[2*maskl+maskr] != masko; - bool xb = gate->_func[2*maskl+(1-maskr)] != masko; - bool xc = gate->_func[2*(1-maskl)+maskr] != masko; - bool xd = gate->_func[2*(1-maskl)+(1-maskr)] != masko; -// printf("xa=%d, xb=%d, xc=%d, xd=%d\n", xa,xb,xc,xd); - - // these are the 0-keys -#ifdef __PURE_SHE__ - Key* outwire_start = _circuit->_sqr_keys + gate->_out*2*_N; -#else - Key* outwire_start = _circuit->_keys + gate->_out*2*_N; +#ifdef DEBUG + std::cout << "garbling gate " << g << std::endl ; #endif - Key* keyxa = outwire_start + (xa?_N:0); - Key* keyxb = outwire_start + (xb?_N:0); - Key* keyxc = outwire_start + (xc?_N:0); - Key* keyxd = outwire_start + (xd?_N:0); - - for(party_id_t i=1; i<=_N; i++) { -// std::cout << "adding to A = " << keyxa[i-1] << std::endl; -// std::cout << "adding to B = " << keyxb[i-1] << std::endl; -// std::cout << "adding to C = " << keyxc[i-1] << std::endl; -// std::cout << "adding to D = " << keyxd[i-1] << std::endl; - *(gg_A+i-1) += keyxa[i-1]; - *(gg_B+i-1) += keyxb[i-1]; - *(gg_C+i-1) += keyxc[i-1]; - *(gg_D+i-1) += keyxd[i-1]; - } + Gate& gate = _circuit->_gates[g]; + registers[gate._out].garble(registers[gate._left], registers[gate._right], + gate._func, &gate, g, prf_outputs, buffers[TYPE_GARBLED_CIRCUIT]); } - - //sending to parties: - fill_message_type(((char*)tbl_start)-4, TYPE_GARBLED_CIRCUIT ); - _node->Broadcast( ((char*)tbl_start)-4 , _G*4*_N*sizeof(Key)+sizeof(MSG_TYPE)); - } -void TrustedParty::Start() +void BaseTrustedParty::_compute_send_garbled_circuit() +{ + SendBuffer& buffer = get_buffer(TYPE_GARBLED_CIRCUIT ); + buffer.allocate(get_garbled_tbl_size() * 4 * get_n_parties() * sizeof(Key)); + garble(); + //sending to parties: +#ifdef DEBUG + cout << "sending garbled circuit" << endl; +#endif +#ifdef DEBUG2 + phex(buffer); +#endif + _node->Broadcast(buffer); + + //prepare_randomness(); +} + +void BaseTrustedParty::Start() { _node->Start(); } -/* keys - a 2*W*n keys buffer to be filled only in the places belong to party pid */ -void TrustedParty::_fill_keys_for_party(Key* keys, party_id_t pid) +bool TrustedParty::_fill_keys() { - int nullfd = open("/dev/urandom", O_RDONLY); - + resize_registers(); for (wire_id_t w=0; w<_W; w++) { - read(nullfd, (char*)(keys+pid-1), sizeof(Key)); - read(nullfd, (char*)(keys+_N+pid-1), sizeof(Key)); -#ifdef __PRIME_FIELD__ - keys[pid-1].adjust(); - keys[pid+_N-1].adjust(); -#endif - keys = keys + 2*_N; + registers[w].init(randomfd, _N); + add_keys(registers[w]); } - close(nullfd); + return true; } #ifdef __PURE_SHE__ @@ -335,56 +359,98 @@ void TrustedParty::_fill_keys_for_party(Key* sqr_keys, Key* keys, party_id_t pid } #endif -/* Merge the two Key buffers into the dest buffer */ -void TrustedParty::_merge_keys(Key* dest, Key* src) -{ - for (wire_id_t w=0; w<_W; w++) { - for (int i=0; i<2; i++) { - for (party_id_t p=0; p<_N; p++) { - int offset = w*2*_N+i*_N+p; - Key kk; - kk = *(src + offset); - dest[offset] += kk; - } - } - } -} - -void TrustedParty::_generate_masks () -{ - char* masks = new char[_W]; - fill_random(masks, _W); - - //need to convert from total random to 0/1 - for (unsigned int i=0 ; i<_W; i++) - { - //because it is a SIGNED char ~half the chars whould be negetives - masks[i] = masks[i]>0 ? 1 : 0; - } - _circuit->Masks(masks); -// printf("masks\n"); -// phex(_circuit->Masks(), _W); -} - - -void TrustedParty::_allocate_prf_outputs() -{ - unsigned int prf_output_size = (PRFS_PER_PARTY(_G, _N)*sizeof(Key)) *_N ; - void* prf_outputs = malloc(prf_output_size); - memset(prf_outputs,0,prf_output_size); - _circuit->Prfs((char*)prf_outputs); -} void TrustedParty::_print_keys() { - Key* key_idx = _circuit->_key(1,0,0); for (wire_id_t w=0; w<_W; w++) { - for(int b=0; b<=1; b++) { - for (party_id_t i=1; i<=_N; i++) { - printf("k^%d_{%u,%d}: ",i,w,b); - std::cout << *key_idx << std::endl; - key_idx++; - } + registers[w].keys.print(w); + } +} + +void TrustedProgramParty::NodeReady() +{ +#ifdef FREE_XOR + for (int i = 0; i < get_n_parties(); i++) + { + SendBuffer& buffer = get_buffer(TYPE_DELTA); + buffer.serialize(deltas[i]); + _node->Send(i + 1, buffer); + } +#endif + this->BaseTrustedParty::NodeReady(); +} + +bool TrustedProgramParty::_fill_keys() +{ + for (int i = 0; i < SPDZ_OP_N; i++) + { + spdz_wires[i].clear(); + spdz_wires[i].resize(get_n_parties()); + } + msg_output_masks = get_buffer(TYPE_MASK_OUTPUT); + return GC::DONE_BREAK == first_phase(program, random_processor, random_machine); +} + +void TrustedProgramParty::garble() +{ + second_phase(program, processor, machine); + + vector< Share > tmp; + 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++) + { + for (int j = 0; j < SPDZ_OP_N; j++) + { + SendBuffer buffer; + fill_message_type(buffer, TYPE_SPDZ_WIRES); + buffer.serialize(j); + buffer.serialize(spdz_wires[j][i].get_data(), spdz_wires[j][i].get_length()); +#ifdef DEBUG_SPDZ_WIRE + cout << "send " << spdz_wires[j][i].get_length() << "/" << buffer.size() + << " bytes for type " << j << " to " << i << endl; +#endif + _node->Send(i + 1, buffer); } } } + +void TrustedProgramParty::store_spdz_wire(SpdzOp op, const Register& reg) +{ + make_share(mask_shares, gf2n(reg.get_mask()), get_n_parties(), gf2n(get_mac_key()), prng); + for (int i = 0; i < get_n_parties(); i++) + { + SpdzWire wire; + wire.mask = mask_shares[i]; + for (int j = 0; j < 2; j++) + { + wire.my_keys[j] = reg.keys[j][i]; + } + wire.pack(spdz_wires[op][i]); + } +#ifdef DEBUG_SPDZ_WIRE + cout << "stored SPDZ wire of type " << op << ":" << endl; + reg.keys.print(reg.get_id()); +#endif +} + +void TrustedProgramParty::store_wire(const Register& reg) +{ + wires.serialize(reg.mask); + reg.keys.serialize(wires); +#ifdef DEBUG + cout << "storing wire" << endl; + reg.print(); +#endif +} + +void TrustedProgramParty::load_wire(Register& reg) +{ + wires.unserialize(reg.mask); + reg.keys.unserialize(wires); +#ifdef DEBUG + cout << "loading wire" << endl; + reg.print(); +#endif +} diff --git a/BMR/TrustedParty.h b/BMR/TrustedParty.h index 76f8ddfc..834f220f 100644 --- a/BMR/TrustedParty.h +++ b/BMR/TrustedParty.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * TrustedParty.h * - * Created on: Feb 15, 2016 - * Author: bush */ #ifndef PROTOCOL_TRUSTEDPARTY_H_ @@ -13,48 +13,150 @@ #include "network/Node.h" #include +#include "Register.h" +#include "CommonParty.h" -class TrustedParty : public NodeUpdatable { +class BaseTrustedParty : virtual public CommonParty { +public: + vector prf_outputs; + + BaseTrustedParty(); + virtual ~BaseTrustedParty() {} + + /* From NodeUpdatable class */ + virtual void NodeReady(); + void NewMessage(int from, ReceivedMsg& msg); + void NodeAborted(struct sockaddr_in* from) { (void)from; } + + void Start(); + +protected: + boost::mutex _print_mx; + + std::atomic_uint _num_prf_received; + std::atomic_uint _received_gc_received; + std::atomic_uint n_received; + + vector msg_keys, msg_input_masks; + + int randomfd; + + bool done_filling; + +#ifdef __PURE_SHE__ + mpz_t _temp_mpz; + void _fill_keys_for_party(Key* sqr_keys, Key* keys, party_id_t pid); +#endif + virtual bool _fill_keys() = 0; + + void _compute_send_garbled_circuit(); + virtual void _launch_online() = 0; + + void prepare_randomness(); + void send_randomness(); + virtual void send_input_masks(party_id_t pid) = 0; + virtual void send_output_masks() = 0; + virtual void garble() = 0; + + void add_keys(const Register& reg); +}; + +class TrustedParty : public BaseTrustedParty, public CommonCircuitParty { public: TrustedParty(const char* netmap_file, const char* circuit_file ); virtual ~TrustedParty(); - /* From NodeUpdatable class */ - void NodeReady(); - void NewMessage(int from, char* message, unsigned int len); - void NodeAborted(struct sockaddr_in* from) {} - - void Start(); - - /* TEST methods */ private: - Node* _node; - BooleanCircuit* _circuit; - gate_id_t _G; - party_id_t _N; - wire_id_t _W; - wire_id_t _OW; - - boost::mutex _print_mx; - - std::atomic_int _num_prf_received; - std::atomic_int _received_gc_received; #ifdef __PURE_SHE__ mpz_t _temp_mpz; void _fill_keys_for_party(Key* sqr_keys, Key* keys, party_id_t pid); #endif - void _fill_keys_for_party(Key* keys, party_id_t pid); - void _merge_keys(Key* dest, Key* src); - void _generate_masks(); - void _allocate_prf_outputs(); - void _allocate_garbled_table(); - void _compute_send_garbled_circuit(); + bool _fill_keys(); + void _launch_online(); void _print_keys(); + void send_input_masks(party_id_t pid); + void send_output_masks(); + void garble(); }; +class TrustedProgramParty : public BaseTrustedParty { +public: + SendBuffer msg_output_masks; + + TrustedProgramParty(int argc, char** argv); + ~TrustedProgramParty(); + + void NodeReady(); + + void store_spdz_wire(SpdzOp op, const Register& reg); + + void store_wire(const Register& reg); + void load_wire(Register& reg); + +#ifdef FREE_XOR + const Key& delta(int i) { return deltas[i]; } + const KeyVector& get_deltas() { return deltas; } +#endif + +private: + friend class GarbleRegister; + friend class RandomRegister; + + static TrustedProgramParty* singleton; + static TrustedProgramParty& s(); + + GC::Memory< GC::Secret::DynamicType > dynamic_memory; + GC::Machine< GC::Secret > machine; + GC::Processor< GC::Secret > processor; + GC::Program< GC::Secret > program; + + GC::Machine< GC::Secret > random_machine; + GC::Processor< GC::Secret > random_processor; + +#ifdef FREE_XOR + KeyVector deltas; +#endif + + vector spdz_wires[SPDZ_OP_N]; + vector< Share > mask_shares; + + Timer random_timer; + + bool _fill_keys(); + void _launch_online(); + + void send_input_masks(party_id_t pid) { (void)pid; } + void send_output_masks(); + void garble(); + + void add_all_keys(const Register& reg, bool external); +}; + + +inline void BaseTrustedParty::add_keys(const Register& reg) +{ + for(int p = 0; p < get_n_parties(); p++) + reg.keys.serialize(msg_keys[p], p + 1); +} + +inline void TrustedProgramParty::add_all_keys(const Register& reg, bool external) +{ + for(int p = 0; p < get_n_parties(); p++) + for (int i = 0; i < get_n_parties(); i++) + reg.keys[external][i].serialize(msg_keys[p]); +} + +inline TrustedProgramParty& TrustedProgramParty::s() +{ + if (singleton) + return *singleton; + else + throw runtime_error("no singleton"); +} + #endif /* PROTOCOL_TRUSTEDPARTY_H_ */ diff --git a/BMR/Wire.h b/BMR/Wire.h index 58e9066e..4bd2217a 100644 --- a/BMR/Wire.h +++ b/BMR/Wire.h @@ -1,12 +1,13 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #ifndef __WIRE_H__ #define __WIRE_H__ #include -#include -#include #include "Key.h" +#include "common.h" class Gate; @@ -16,10 +17,10 @@ typedef char signal_t; typedef struct Wire { // signal_t _sig; // the actual value that is passing through the wire (after inputs have been set) std::vector _enters_to; //TODO make it a regular c array - gate_id_t _out_from; bool _is_output; + gate_id_t _out_from; - Wire(bool out):/*_sig(NO_SIGNAL),*/ _is_output(out),_out_from(NULL){} + Wire(bool out):/*_sig(NO_SIGNAL),*/ _is_output(out),_out_from(0){} // inline signal_t Sig() { return _sig; } // inline void Sig(signal_t s) { _sig = s; } // void print(int w_id) { diff --git a/BMR/aes.cpp b/BMR/aes.cpp index 3cf01bc9..5e356bc1 100644 --- a/BMR/aes.cpp +++ b/BMR/aes.cpp @@ -1,3 +1,5 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #include "aes.h" #ifdef _WIN32 diff --git a/BMR/common.h b/BMR/common.h index 2613aff1..740b9145 100644 --- a/BMR/common.h +++ b/BMR/common.h @@ -1,15 +1,53 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * common.h * - * Created on: Jan 21, 2016 - * Author: bush */ #ifndef CIRCUIT_INC_COMMON_H_ #define CIRCUIT_INC_COMMON_H_ +#include typedef unsigned long wire_id_t; typedef unsigned long gate_id_t; +class Function { + bool rep[4]; + int shift(int i) { return 4 * (3 - i); } +public: + Function() { memset(rep, 0, sizeof(rep)); } + Function(std::string& func) + { + for (int i = 0; i < 4; i++) + if (func[i] != '0') + rep[i] = 1; + else + rep[i] = 0; + } + Function(int int_rep) + { + for (int i = 0; i < 4; i++) + rep[i] = (int_rep << shift(i)) & 1; + } + uint8_t operator[](int i) { return rep[i]; } +}; + +template +class CheckVector : public vector +{ +public: + CheckVector() : vector() {} + CheckVector(size_t size) : vector(size) {} + CheckVector(size_t size, const T& def) : vector(size, def) {} +#ifdef CHECK_SIZE + T& operator[](size_t i) { return this->at(i); } + const T& operator[](size_t i) const { return this->at(i); } +#else + T& at(size_t i) { return (*this)[i]; } + const T& at(size_t i) const { return (*this)[i]; } +#endif +}; + #endif /* CIRCUIT_INC_COMMON_H_ */ diff --git a/BMR/msg_types.cpp b/BMR/msg_types.cpp new file mode 100644 index 00000000..fdb77c9b --- /dev/null +++ b/BMR/msg_types.cpp @@ -0,0 +1,16 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * msg_types.cpp + * + */ + +#include "msg_types.h" + +#define X(NAME) #NAME, + +const char* message_type_names[] = { + MESSAGE_TYPES +}; + +#undef X diff --git a/BMR/msg_types.h b/BMR/msg_types.h index 2d4ed92f..b4db120c 100644 --- a/BMR/msg_types.h +++ b/BMR/msg_types.h @@ -1,30 +1,42 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * msg_types.h * - * Created on: Feb 16, 2016 - * Author: bush */ #ifndef PROTOCOL_INC_MSG_TYPES_H_ #define PROTOCOL_INC_MSG_TYPES_H_ -typedef enum { - TYPE_KEYS = 0, - TYPE_MASK_INPUTS, - TYPE_MASK_OUTPUT, - TYPE_PRF_OUTPUTS, - TYPE_GARBLED_CIRCUIT, - TYPE_EXTERNAL_VALUES, - TYPE_ALL_EXTERNAL_VALUES, - TYPE_KEY_PER_IN_WIRE, - TYPE_ALL_KEYS_PER_IN_WIRE, - TYPE_LAUNCH_ONLINE, - TYPE_RECEIVED_GC, +#define MESSAGE_TYPES \ + X(TYPE_KEYS) \ + X(TYPE_MASK_INPUTS) \ + X(TYPE_MASK_OUTPUT) \ + X(TYPE_PRF_OUTPUTS) \ + X(TYPE_GARBLED_CIRCUIT) \ + X(TYPE_EXTERNAL_VALUES) \ + X(TYPE_ALL_EXTERNAL_VALUES) \ + X(TYPE_KEY_PER_IN_WIRE) \ + X(TYPE_ALL_KEYS_PER_IN_WIRE) \ + X(TYPE_LAUNCH_ONLINE) \ + X(TYPE_RECEIVED_GC) \ + X(TYPE_SPDZ_WIRES) \ + X(TYPE_DELTA) \ + X(TYPE_CHECKSUM) \ + X(TYPE_NEXT) \ + X(TYPE_DONE) \ + X(TYPE_MAX) \ - TYPE_CHECKSUM, - TYPE_MAX + +#define X(NAME) NAME, + +typedef enum { +MESSAGE_TYPES } MSG_TYPE; +#undef X + +extern const char* message_type_names[]; #endif /* PROTOCOL_INC_MSG_TYPES_H_ */ diff --git a/BMR/network/Client.cpp b/BMR/network/Client.cpp index 7e8f785c..061f3ffa 100644 --- a/BMR/network/Client.cpp +++ b/BMR/network/Client.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Client.cpp * - * Created on: Jan 27, 2016 - * Author: bush */ #include "Client.h" @@ -28,20 +28,15 @@ static void throw_bad_ip(const char* ip) { } Client::Client(endpoint_t* endpoints, int numservers, ClientUpdatable* updatable, unsigned int max_message_size) - :_numservers(numservers), - _max_msg_sz(max_message_size), - _updatable(updatable), - _new_message(false) + :_max_msg_sz(max_message_size), + _numservers(numservers), + _updatable(updatable) { _sockets = new int[_numservers](); // 0 initialized _servers = new struct sockaddr_in[_numservers]; - _msg_queues = new Queue[_numservers](); + _msg_queues = new WaitQueue< shared_ptr >[_numservers]; - _lockqueue = new std::mutex[_numservers]; - _queuecheck = new std::condition_variable[_numservers]; - _new_message = new bool[_numservers](); - - memset(_servers, 0, sizeof(_servers)); + memset(_servers, 0, sizeof(*_servers)); for (int i=0; i<_numservers; i++) { _sockets[i] = socket(AF_INET, SOCK_STREAM, 0); @@ -56,20 +51,32 @@ Client::Client(endpoint_t* endpoints, int numservers, ClientUpdatable* updatable } Client::~Client() { + Stop(); for (int i=0; i<_numservers; i++) close(_sockets[i]); delete[] _sockets; delete[] _servers; delete[] _msg_queues; - delete[] _lockqueue; - delete[] _queuecheck; - delete[] _new_message; +#ifdef DEBUG_COMM + printf("Client:: Client deleted\n"); +#endif } void Client::Connect() { for (int i=0; i<_numservers; i++) - new boost::thread(&Client::_send_thread, this, i); - new boost::thread(&Client::_connect, this); + threads.add_thread(new boost::thread(&Client::_send_thread, this, i)); + threads.add_thread(new boost::thread(&Client::_connect, this)); +} + +void Client::Stop() { + for (int i=0; i<_numservers; i++) + _msg_queues[i].stop(); + threads.join_all(); + for (int i=0; i<_numservers; i++) + shutdown(_sockets[i], SHUT_RDWR); +#ifdef DEBUG_COMM + printf("Stopped client\n"); +#endif } void Client::_connect() { @@ -89,95 +96,100 @@ void Client::_connect_to_server(int i) { int port = ntohs(_servers[i].sin_port); ip = inet_ntoa(_servers[i].sin_addr); int error = 0; + int interval = 10000; + int total_wait = 0; while (true ) { error = connect(_sockets[i], (struct sockaddr *)&_servers[i], sizeof(struct sockaddr)); + if (interval < CONNECT_INTERVAL) + interval *= 2; if(!error) break; if (errno == 111) { fprintf(stderr,"."); } else { fprintf(stderr,"Client:: Error (%d): connect to %s:%d: \"%s\"\n",errno, ip,port,strerror(errno)); - fprintf(stderr,"Client:: socket %d sleeping for %u usecs\n",i, CONNECT_INTERVAL); + fprintf(stderr,"Client:: socket %d sleeping for %u usecs\n",i, interval); } - usleep(CONNECT_INTERVAL); + usleep(interval); + total_wait += interval; + if (total_wait > 60e6) + throw runtime_error("waiting for too long"); } printf("\nClient:: connected to %s:%d\n", ip,port); - setsockopt(_sockets[i], SOL_SOCKET, SO_SNDBUF, &BUFFER_SIZE, sizeof(BUFFER_SIZE)); + // Using the following disables the automatic buffer size (ipv4.tcp_wmem) + // in favour of the core.wmem_max, which is worse. + //setsockopt(_sockets[i], SOL_SOCKET, SO_SNDBUF, &NETWORK_BUFFER_SIZE, sizeof(NETWORK_BUFFER_SIZE)); } -void Client::Send(int id, const char* message, unsigned int len) { - Msg new_msg = {message, len}; +void Client::Send(int id, SendBuffer& buffer) { { - std::unique_lock locker(_lockqueue[id]); -// printf ("Client:: queued %u bytes to %d\n", len, id); - _msg_queues[id].Enqueue(new_msg); - _new_message[id] = true; - _queuecheck[id].notify_one(); +#ifdef DEBUG_COMM + printf ("Client:: queued %u bytes to %d\n", buffer.size(), id); + phex(buffer.data(), 4); +#endif + SendBuffer* tmp = new SendBuffer; + *tmp = buffer; + shared_ptr new_msg(tmp); + _msg_queues[id].push(new_msg); } } -void Client::Broadcast(const char* message, unsigned int len) { +void Client::Broadcast(SendBuffer& buffer) { +#ifdef DEBUG_COMM + printf ("Client:: queued %u bytes to broadcast\n", buffer.size()); + phex(buffer.data(), 4); +#endif + SendBuffer* tmp = new SendBuffer; + *tmp = buffer; + shared_ptr new_msg(tmp); for(int i=0;i<_numservers; i++) { - std::unique_lock locker(_lockqueue[i]); - Msg new_msg = {message, len}; - _msg_queues[i].Enqueue(new_msg); - _new_message[i] = true; - _queuecheck[i].notify_one(); + _msg_queues[i].push(new_msg); } } -void Client::Broadcast2(const char* message, unsigned int len) { +void Client::Broadcast2(SendBuffer& buffer) { +#ifdef DEBUG_COMM + printf ("Client:: queued %u bytes to broadcast to all but the server\n", buffer.size()); + phex(buffer.data(), 4); +#endif + SendBuffer* tmp = new SendBuffer; + *tmp = buffer; + shared_ptr new_msg(tmp); // first server is always the trusted party so we start with i=1 for(int i=1;i<_numservers; i++) { - std::unique_lock locker(_lockqueue[i]); - Msg new_msg = {message, len}; - _msg_queues[i].Enqueue(new_msg); - _new_message[i] = true; - _queuecheck[i].notify_one(); + _msg_queues[i].push(new_msg); } } void Client::_send_thread(int i) { - while(true) - { - { - std::unique_lock locker(_lockqueue[i]); - //printf("Client:: waiting for a notification to send to %d\n", i); - _queuecheck[i].wait(locker); - if (!_new_message[i]) { -// printf("Client:: Spurious notification!\n"); - continue; - } - //printf("Client:: notified!!\n"); - } - while (true) - { - Msg msg = {0}; - { - std::unique_lock locker(_lockqueue[i]); - if(_msg_queues[i].Empty()) { - //printf("Client:: no more messages in queue\n"); - break; // out of the inner while - } - msg = _msg_queues[i].Dequeue(); - } - _send_blocking(msg, i); - } - _new_message[i] = false; - } + shared_ptr msg; + while(_msg_queues[i].pop_dont_stop(msg)) + _send_blocking(*msg, i); +#ifdef DEBUG_COMM + printf("Shutting down sender thread %d\n", i); +#endif } -void Client::_send_blocking(Msg msg, int id) { -// printf ("Client:: sending %u bytes to %d\n", msg.len, id); +void Client::_send_blocking(SendBuffer& msg, int id) { +#ifdef DEBUG_COMM + printf ("Client:: sending %llu bytes at 0x%x to %d\n", msg.size(), msg.data(), id); + fflush(0); +#ifdef DEBUG2 + phex(msg.data(), msg.size()); +#else + phex(msg.data(), 4); +#endif +#endif int cur_sent = 0; - cur_sent = send(_sockets[id], &msg.len, LENGTH_FIELD, 0); - if(LENGTH_FIELD == cur_sent) { + size_t len = msg.size(); + cur_sent = send(_sockets[id], &len, sizeof(len), 0); + if(sizeof(len) == cur_sent) { unsigned int total_sent = 0; unsigned int remaining = 0; - while(total_sent != msg.len) { - remaining = (msg.len-total_sent)>_max_msg_sz ? _max_msg_sz : (msg.len-total_sent); - cur_sent = send(_sockets[id], msg.msg+total_sent, remaining, 0); + while(total_sent != msg.size()) { + remaining = (msg.size()-total_sent)>_max_msg_sz ? _max_msg_sz : (msg.size()-total_sent); + cur_sent = send(_sockets[id], msg.data()+total_sent, remaining, 0); //printf("Client:: msg.len=%u, remaining=%u, total_sent=%u, cur_sent = %d\n",msg.len, remaining, total_sent,cur_sent); if(cur_sent == -1) { fprintf(stderr,"Client:: Error: send msg failed: %s\n",strerror(errno)); @@ -188,4 +200,10 @@ void Client::_send_blocking(Msg msg, int id) { } else if (-1 == cur_sent){ fprintf(stderr,"Client:: Error: send header failed: %s\n",strerror(errno)); } +#ifdef DEBUG_COMM + printf ("Client:: sent %u bytes at 0x%x to %d\n", msg.size(), msg.data(), id); + fflush(0); + phex(msg.data(), 4); + fflush(0); +#endif } diff --git a/BMR/network/Client.h b/BMR/network/Client.h index 7b0bd78f..28d8f108 100644 --- a/BMR/network/Client.h +++ b/BMR/network/Client.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Client.h * - * Created on: Jan 27, 2016 - * Author: bush */ #ifndef NETWORK_INC_CLIENT_H_ @@ -17,6 +17,10 @@ #include #include #include +#include + +#include "Tools/WaitQueue.h" +#include "Tools/FlexBuffer.h" #define CONNECT_INTERVAL (1000000) @@ -34,22 +38,20 @@ public: virtual ~Client(); void Connect(); - void Send(int id, const char* message, unsigned int len); - void Broadcast(const char* message, unsigned int len); - void Broadcast2(const char* message, unsigned int len); + void Send(int id, SendBuffer& new_msg); + void Broadcast(SendBuffer& new_msg); + void Broadcast2(SendBuffer& new_msg); + void Stop(); private: - Queue* _msg_queues; + WaitQueue< shared_ptr >* _msg_queues; // std::queue* _msg_queues; // boost::mutex* _msg_mux; // boost::mutex* _thd_mux; unsigned int _max_msg_sz; - std::mutex* _lockqueue; - std::condition_variable* _queuecheck; - bool* _new_message; void _send_thread(int i); - void _send_blocking(Msg msg, int id); + void _send_blocking(SendBuffer& msg, int id); void _connect(); void _connect_to_server(int i); @@ -58,6 +60,8 @@ private: struct sockaddr_in* _servers; int* _sockets; ClientUpdatable* _updatable; + + boost::thread_group threads; }; #endif /* NETWORK_INC_CLIENT_H_ */ diff --git a/BMR/network/Node.cpp b/BMR/network/Node.cpp index a9723076..66607af2 100644 --- a/BMR/network/Node.cpp +++ b/BMR/network/Node.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Node.cpp * - * Created on: Jan 27, 2016 - * Author: bush */ #include @@ -26,12 +26,12 @@ static void throw_bad_id(int id) { Node::Node(const char* netmap_file, int my_id, NodeUpdatable* updatable, int num_parties) :_id(my_id), - _updatable(updatable), _connected_to_servers(false), - _num_parties_identified(0) + _num_parties_identified(0), + _updatable(updatable) { _parse_map(netmap_file, num_parties); - unsigned int max_message_size = BUFFER_SIZE/2; + unsigned int max_message_size = NETWORK_BUFFER_SIZE/2; if(_id < 0 || _id > _numparties) throw_bad_id(_id); _ready_nodes = new bool[_numparties](); //initialized to false @@ -41,21 +41,30 @@ Node::Node(const char* netmap_file, int my_id, NodeUpdatable* updatable, int num } Node::~Node() { + print_waiting(); delete(_client); delete(_server); - delete (_endpoints); - delete (_ready_nodes); - delete (_clients_connected); + delete[] (_endpoints); + delete[] (_ready_nodes); + delete[] (_clients_connected); } void Node::Start() { _client->Connect(); - new boost::thread(&Node::_start, this); + boost::thread(&Node::_start, this).join(); + _server->starter->join(); + for (unsigned int i = 0; i < _server->listeners.size(); i++) + _server->listeners[i]->join(); +} + +void Node::Stop() { + _client->Stop(); } void Node::_start() { - usleep(START_INTERVAL); + int interval = 10000; + int total_wait = 0; while(true) { bool all_ready = true; if (_connected_to_servers) { @@ -72,15 +81,27 @@ void Node::_start() { break; fprintf(stderr,"+"); // fprintf(stderr,"Node:: waiting for all nodes to get ready ; sleeping for %u usecs\n", START_INTERVAL); - usleep(START_INTERVAL); + if (interval < CONNECT_INTERVAL) + interval *= 2; + usleep(interval); + total_wait += interval; + if (total_wait > 60e6) + throw runtime_error("waiting for too long"); } printf("All identified\n"); - _client->Broadcast(ALL_IDENTIFIED,strlen(ALL_IDENTIFIED)); + SendBuffer buffer; + buffer.serialize(ALL_IDENTIFIED, strlen(ALL_IDENTIFIED)); + _client->Broadcast(buffer); } -void Node::NewMsg(char* msg, unsigned int len, struct sockaddr_in* from) { - //printf("Node:: got message of length %d ",len); -// printf("from %s:%d\n", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); +void Node::NewMsg(ReceivedMsg& message, struct sockaddr_in* from) { + char* msg = message.data(); + size_t len = message.size(); +#ifdef DEBUG_COMM + printf("Node:: got message of length %u at 0x%x\n",len,msg); + printf("from %s:%d\n", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); + phex(msg, 4); +#endif if(len == strlen(ID_HDR)+sizeof(_id) && 0==strncmp(msg, ID_HDR, strlen(ID_HDR))) { int *id = (int*)(msg+strlen(ID_HDR)); printf("Node:: identified as party: %d\n", *id); @@ -94,12 +115,16 @@ void Node::NewMsg(char* msg, unsigned int len, struct sockaddr_in* from) { printf("Node:: received ALL_IDENTIFIED from %d\n",_clientsmap[from]); _num_parties_identified++; if(_num_parties_identified == _numparties-1) { - printf("Node:: received ALL_IDENTIFIED from ALL\n",_clientsmap[from]); + printf("Node:: received ALL_IDENTIFIED from ALL\n"); _updatable->NodeReady(); } return; } - _updatable->NewMessage(_clientsmap[from], msg, len ); + _updatable->NewMessage(_clientsmap[from], message); +#ifdef DEBUG_COMM + printf("finished with %d bytes at 0x%x\n", len, msg); + phex(msg, 4); +#endif } void Node::ClientsConnected() { @@ -109,6 +134,7 @@ void Node::ClientsConnected() { void Node::NodeAborted(struct sockaddr_in* from) { printf("Node:: party %d has aborted\n",_clientsmap[from]); + Stop(); } void Node::ConnectedToServers() { @@ -117,25 +143,43 @@ void Node::ConnectedToServers() { _identify(); } -void Node::Send(int to, const char* msg, unsigned int len) { +void Node::Send(int to, SendBuffer& msg) { int new_recipient = to>_id?to-1:to; - //printf("Node:: new_recipient=%d\n",new_recipient); - _client->Send(new_recipient, msg, len); +#ifdef DEBUG_COMM + printf("Node:: new_recipient=%d\n",new_recipient); + printf("Send %d bytes at 0x%x\n", msg.size(), msg.data()); + phex(msg.data(), 4); +#endif + _client->Send(new_recipient, msg); } -void Node::Broadcast(const char* msg, unsigned int len) { - _client->Broadcast(msg, len); +void Node::Broadcast(SendBuffer& msg) { +#ifdef DEBUG_COMM + printf("Broadcast %d bytes at 0x%x\n", msg.size(), msg.data()); + phex(msg.data(), 4); +#endif + _client->Broadcast(msg); } -void Node::Broadcast2(const char* msg, unsigned int len) { - _client->Broadcast2(msg, len); +void Node::Broadcast2(SendBuffer& msg) { +#ifdef DEBUG_COMM + printf("Broadcast2 %d bytes at 0x%x\n", msg.size(), msg.data()); + phex(msg.data(), 4); +#endif + _client->Broadcast2(msg); } void Node::_identify() { - char* msg = new char[strlen(ID_HDR)+sizeof(_id)]; + char* msg = id_msg; strncpy(msg, ID_HDR, strlen(ID_HDR)); strncpy(msg+strlen(ID_HDR), (const char *)&_id, sizeof(_id)); //printf("Node:: identifying myself:\n"); - _client->Broadcast(msg,strlen(ID_HDR)+4); + SendBuffer buffer; + buffer.serialize(msg, strlen(ID_HDR)+4); +#ifdef DEBUG_COMM + cout << "message for identification:"; + phex(buffer.data(), 4); +#endif + _client->Broadcast(buffer); } void Node::_parse_map(const char* netmap_file, int num_parties) { @@ -165,11 +209,27 @@ void Node::_parse_map(const char* netmap_file, int num_parties) { for(int i=0; i<_numparties; i++) { if(_id == i) { netmap >> _ip >> _port; - //printf("Node:: my address: %s:%d\n", _ip.c_str(),_port); +#ifdef DEBUG_NETMAP + printf("Node:: my address: %s:%d\n", _ip.c_str(),_port); +#endif continue; } netmap >> _endpoints[j].ip >> _endpoints[j].port; +#ifdef DEBUG_NETMAP + printf("Node:: other address (%d): %s:%d\n", j, + _endpoints[j].ip.c_str(), _endpoints[j].port); +#endif j++; } } } + +void Node::print_waiting() +{ + for (unsigned i = 0; i < _server->timers.size(); i++) + { + cout << "Waited " << _server->timers[i].elapsed() + << " seconds for client " + << _clientsmap[_server->get_client_addr(i)] << endl; + } +} diff --git a/BMR/network/Node.h b/BMR/network/Node.h index 1602d289..bf69c401 100644 --- a/BMR/network/Node.h +++ b/BMR/network/Node.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Node.h * - * Created on: Jan 27, 2016 - * Author: bush */ #ifndef NETWORK_NODE_H_ @@ -11,11 +11,14 @@ #include #include #include +#include #include "common.h" #include "Client.h" #include "Server.h" +#include "Tools/FlexBuffer.h" + class Server; class Client; class ServerUpdatable; @@ -24,7 +27,7 @@ class ClientUpdatable; class NodeUpdatable { public: virtual void NodeReady()=0; - virtual void NewMessage(int from, char* message, unsigned int len) =0; + virtual void NewMessage(int from, ReceivedMsg& msg) =0; virtual void NodeAborted(struct sockaddr_in* from) =0; }; @@ -34,26 +37,29 @@ typedef void (*msg_id_cb_t)(int from, char* msg, unsigned int len); const char ALL_IDENTIFIED[] = "ALID"; #define LOOPBACK NULL #define LOCALHOST_IP "127.0.0.1" -#define PORT_BASE (4000) +#define PORT_BASE (14000) class Node : public ServerUpdatable, public ClientUpdatable { public: Node(const char* netmap_file, int my_id, NodeUpdatable* updatable, int num_parties=0); virtual ~Node(); - void Send(int to, const char* msg, unsigned int len); - void Broadcast(const char* msg, unsigned int len); - void Broadcast2(const char* msg, unsigned int len); + void Send(int to, SendBuffer& msg); + void Broadcast(SendBuffer& msg); + void Broadcast2(SendBuffer& msg); inline int NumParties(){return _numparties;} void Start(); + void Stop(); // void Close(); //derived from ServerUpdateable - void NewMsg(char* msg, unsigned int len, struct sockaddr_in* from); + void NewMsg(ReceivedMsg& msg, struct sockaddr_in* from); void ClientsConnected(); void NodeAborted(struct sockaddr_in* from); //derived from ClientUpdatable void ConnectedToServers(); + void print_waiting(); + private: void _parse_map(const char* netmap_file, int num_parties); void _identify(); @@ -74,6 +80,8 @@ private: std::map _clientsmap; bool* _clients_connected; NodeUpdatable* _updatable; + + char id_msg[strlen(ID_HDR)+sizeof(_id)]; }; #endif /* NETWORK_NODE_H_ */ diff --git a/BMR/network/Server.cpp b/BMR/network/Server.cpp index e051e106..37639af9 100644 --- a/BMR/network/Server.cpp +++ b/BMR/network/Server.cpp @@ -1,3 +1,5 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + #include #include @@ -9,19 +11,21 @@ #include #include #include +#include #include "Server.h" - /* Opens server socket for listening - not yet accepting */ Server::Server(int port, int expected_clients, ServerUpdatable* updatable, unsigned int max_message_size) - :_port(port), + :starter(0), _expected_clients(expected_clients), + _port(port), _updatable(updatable), _max_msg_sz(max_message_size) { _clients = new int[expected_clients](); _clients_addr = new struct sockaddr_in[expected_clients](); + timers.resize(expected_clients); _servfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == _servfd) @@ -41,16 +45,21 @@ Server::Server(int port, int expected_clients, ServerUpdatable* updatable, unsig printf("Server:: Error listen: \n%s\n",strerror(errno)); - new boost::thread(&Server::_start_server, this); + starter = new boost::thread(&Server::_start_server, this); } Server::~Server() { +#ifdef DEBUG_COMM printf("Server:: Server being deleted\n"); +#endif close(_servfd); for (int i=0; i<_expected_clients; i++) close(_clients[i]); - delete (_clients); - delete (_clients_addr); + delete[] (_clients); + delete[] (_clients_addr); + delete starter; + for (unsigned i = 0; i < listeners.size(); i++) + delete listeners[i]; } void Server::_start_server() { @@ -64,8 +73,10 @@ void Server::_start_server() { printf("Server:: accept: error in connecting socket\n%s\n",strerror(errno)); } else { printf("Server:: Incoming connection from %s:%d\n",inet_ntoa(_clients_addr[i].sin_addr), ntohs(_clients_addr[i].sin_port)); - setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &BUFFER_SIZE, sizeof(BUFFER_SIZE)); - boost::thread* listener = new boost::thread(&Server::_listen_to_client, this, i); + // Using the following disables the automatic buffer size (ipv4.tcp_rmem) + // in favour of the core.rmem_max, which is worse. + //setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &NETWORK_BUFFER_SIZE, sizeof(NETWORK_BUFFER_SIZE)); + listeners.push_back(new boost::thread(&Server::_listen_to_client, this, i)); } } @@ -73,23 +84,32 @@ void Server::_start_server() { } void Server::_listen_to_client(int id){ - int msg_len = 0; + size_t msg_len = 0; int n_recv = 0; - unsigned int total_received; - unsigned int remaining; - char *msg; + size_t total_received; + size_t remaining; + ReceivedMsg msg; +#ifdef DEBUG_FLEXBUF + cout << "msg from " << id << " stored at " << &msg << endl; +#endif while (true) { - n_recv = recv(_clients[id], &msg_len, LENGTH_FIELD, MSG_WAITALL); - if (!_handle_recv_len(id, n_recv,LENGTH_FIELD)) + timers[id].start(); + n_recv = recv(_clients[id], &msg_len, sizeof(msg_len), MSG_WAITALL); + timers[id].stop(); +#ifdef DEBUG_COMM + cout << "message of size " << msg_len << " coming in from " << id << endl; +#endif + msg.resize(msg_len); + if (!_handle_recv_len(id, n_recv, sizeof(msg_len))) return; // printf("Server:: waiting for a message of len = %d\n", msg_len); - msg = new char[msg_len]; - assert(msg != NULL); total_received = 0; remaining = 0; while (total_received != msg_len) { remaining = (msg_len-total_received)>_max_msg_sz ? _max_msg_sz : (msg_len-total_received); - n_recv = recv(_clients[id], msg+total_received, remaining, NULL /* MSG_WAITALL*/); + timers[id].start(); + n_recv = recv(_clients[id], msg.data()+total_received, remaining, 0 /* MSG_WAITALL*/); + timers[id].stop(); // printf("n_recv = %d\n", n_recv); if (!_handle_recv_len(id, n_recv,remaining)) { printf("returning\n"); @@ -99,19 +119,21 @@ void Server::_listen_to_client(int id){ // printf("total_received = %d\n", total_received); } // printf("Server:: received %d: \n", msg_len); - _updatable->NewMsg(msg, msg_len, &_clients_addr[id]); + _updatable->NewMsg(msg, &_clients_addr[id]); } printf("stop listenning to %d\n", id); } -bool Server::_handle_recv_len(int id, unsigned int actual_len, unsigned int expected_len) { +bool Server::_handle_recv_len(int id, size_t actual_len, size_t expected_len) { // printf("Server:: received msg from %d len = %u\n",id, actual_len); if (actual_len == 0) { +#ifdef DEBUG_COMM printf("Server:: [%d]: Error: n_recv==0 Connection closed\n", id); +#endif _updatable->NodeAborted(&_clients_addr[id]); return false; // exit(1); - } else if (actual_len == -1) { + } else if (actual_len == -1U) { printf("Server:: [%d]: Error: n_recv==-1. \"%s\"\n",id, strerror(errno)); _updatable->NodeAborted(&_clients_addr[id]); return false; @@ -120,4 +142,5 @@ bool Server::_handle_recv_len(int id, unsigned int actual_len, unsigned int expe // printf("Server:: [%d]: Error: n_recv < %d; n_recv=%d; \"%d\"\n",id, expected_len, actual_len,strerror(errno)); return true; } + return true; } diff --git a/BMR/network/Server.h b/BMR/network/Server.h index 871fa4a4..e9c8a224 100644 --- a/BMR/network/Server.h +++ b/BMR/network/Server.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * Server.h * - * Created on: Jan 24, 2016 - * Author: bush */ #ifndef NETWORK_INC_SERVER_H_ @@ -10,13 +10,15 @@ #include #include +#include #include "common.h" +#include "Tools/FlexBuffer.h" class ServerUpdatable { public: virtual void ClientsConnected()=0; - virtual void NewMsg(char* msg, unsigned int len, struct sockaddr_in* from)=0; + virtual void NewMsg(ReceivedMsg& msg, struct sockaddr_in* from)=0; virtual void NodeAborted(struct sockaddr_in* from) =0; }; @@ -25,6 +27,13 @@ public: Server(int port, int expected_clients, ServerUpdatable* updatable, unsigned int max_message_size); ~Server(); + sockaddr_in* get_client_addr(int id) { return &_clients_addr[id]; } + + boost::thread* starter; + std::vector listeners; + + vector timers; + private: int _expected_clients; int *_clients; @@ -38,7 +47,7 @@ private: void _start_server(); void _listen_to_client(int id); - bool _handle_recv_len(int id, unsigned int actual_len,unsigned int expected_len); + bool _handle_recv_len(int id, size_t actual_len, size_t expected_len); }; diff --git a/BMR/network/common.h b/BMR/network/common.h index a5140887..b8bb7423 100644 --- a/BMR/network/common.h +++ b/BMR/network/common.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * common.h * - * Created on: Jan 27, 2016 - * Author: bush */ #ifndef NETWORK_INC_COMMON_H_ @@ -13,23 +13,16 @@ //#include "utils.h" -#define LENGTH_FIELD (4) - /* * To change the buffer sizes in the kernel # echo 'net.core.wmem_max=12582912' >> /etc/sysctl.conf # echo 'net.core.rmem_max=12582912' >> /etc/sysctl.conf */ -const int BUFFER_SIZE = 20000000; +const int NETWORK_BUFFER_SIZE = 20000000; typedef struct { std::string ip; int port; } endpoint_t; -typedef struct { - const char* msg; - unsigned int len; -} Msg; - #endif /* NETWORK_INC_COMMON_H_ */ diff --git a/BMR/network/makefile b/BMR/network/makefile deleted file mode 100644 index 33d4d6c6..00000000 --- a/BMR/network/makefile +++ /dev/null @@ -1,43 +0,0 @@ - - - - -CPPFLAGS=-g -O3 -c -w --std=c++11 \ - -I/usr/include \ - -Iinc \ - $(LOCAL_CPPFLAGS) - -LDFLAGS=-g -L/usr/lib/x86_64-linux-gnu/ \ - -lboost_system -lpthread -lboost_thread $(LOCAL_LDFLAGS) - -OBJECTS=build/test.o \ - build/utils.o \ - build/Server.o \ - build/Client.o \ - build/Node.o - - -all:bin/net - -bin/net:$(OBJECTS) - g++ -Wall $^ -o bin/net $(LDFLAGS) - - -build/Server.o:src/Server.cpp - $(CC) $(CPPFLAGS) $^ -o $@ - -build/Client.o:src/Client.cpp - $(CC) $(CPPFLAGS) $^ -o $@ - -build/Node.o:src/Node.cpp - $(CC) $(CPPFLAGS) $^ -o $@ - -build/test.o:test/test.cpp - $(CC) $(CPPFLAGS) $^ -o $@ - -build/utils.o:src/utils.cpp - $(CC) $(CPPFLAGS) $^ -o $@ - - -clean: - rm build/* bin/net \ No newline at end of file diff --git a/BMR/network/mq.h b/BMR/network/mq.h index c0eddb70..a67450b1 100644 --- a/BMR/network/mq.h +++ b/BMR/network/mq.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * mq.h * - * Created on: Feb 14, 2016 - * Author: bush */ #ifndef NETWORK_INC_MQ_H_ diff --git a/BMR/network/utils.cpp b/BMR/network/utils.cpp index 6290d6b4..f6704e6d 100644 --- a/BMR/network/utils.cpp +++ b/BMR/network/utils.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * utils.cpp * - * Created on: Jan 31, 2016 - * Author: bush */ @@ -11,6 +11,7 @@ #include #include #include +#include #include "utils.h" @@ -22,7 +23,7 @@ void fill_random(void* buffer, unsigned int length) } char cs(char* msg, unsigned int len, char result) { - for(int i = 0; i < len; i++) + for(size_t i = 0; i < len; i++) result += msg[i]; return result; } diff --git a/BMR/network/utils.h b/BMR/network/utils.h index 1543205d..6b4dbc69 100644 --- a/BMR/network/utils.h +++ b/BMR/network/utils.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * utils.h * - * Created on: Jan 31, 2016 - * Author: bush */ #ifndef NETWORK_TEST_UTILS_H_ diff --git a/BMR/prf.cpp b/BMR/prf.cpp index 5e84db51..c6955ebe 100644 --- a/BMR/prf.cpp +++ b/BMR/prf.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * prf.cpp * - * Created on: Feb 18, 2016 - * Author: bush */ @@ -10,22 +10,14 @@ #include "aes.h" #include "proto_utils.h" -void PRF_single(const Key* key, char* input, char* output) +void PRF_single(const Key& key, char* input, char* output) { // printf("prf_single\n"); // std::cout << *key; // phex(input, 16); AES_KEY aes_key; - AES_128_Key_Expansion((const unsigned char*)(&(key->r)), &aes_key); + AES_128_Key_Expansion((const unsigned char*)(&(key.r)), &aes_key); aes_key.rounds=10; AES_encryptC((block*)input, (block*)output, &aes_key); // phex(output, 16); } - -void PRF_chunk(const Key* key, char* input, char* output, int number) -{ - AES_KEY aes_key; - AES_128_Key_Expansion((const unsigned char*)(&(key->r)), &aes_key); - aes_key.rounds=10; - AES_ecb_encrypt_chunk_in_out((block*)input, (block*)output, number, &aes_key); -} diff --git a/BMR/prf.h b/BMR/prf.h index 9f3c4e1a..236528ab 100644 --- a/BMR/prf.h +++ b/BMR/prf.h @@ -1,16 +1,37 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * prf.h * - * Created on: Feb 18, 2016 - * Author: bush */ #ifndef PROTOCOL_INC_PRF_H_ #define PROTOCOL_INC_PRF_H_ #include "Key.h" +#include "aes.h" -void PRF_single(const Key* key, char* input, char* output); -void PRF_chunk(const Key* key, char* input, char* output, int number); +#include "Tools/aes.h" + +void PRF_single(const Key& key, char* input, char* output); + +inline void PRF_chunk(const Key& key, char* input, char* output, int number) +{ + __m128i* in = (__m128i*)input; + __m128i* out = (__m128i*)output; + AES_KEY aes_key; + AES_128_Key_Expansion((unsigned char*)&key.r, &aes_key); + switch (number) + { + case 2: + ecb_aes_128_encrypt<2>(out, in, (octet*)aes_key.rd_key); + break; + case 3: + ecb_aes_128_encrypt<3>(out, in, (octet*)aes_key.rd_key); + break; + default: + throw not_implemented(); + } +} #endif /* PROTOCOL_INC_PRF_H_ */ diff --git a/BMR/proto_utils.cpp b/BMR/proto_utils.cpp index 2835b678..5fa5bc3c 100644 --- a/BMR/proto_utils.cpp +++ b/BMR/proto_utils.cpp @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * utils.cpp * - * Created on: Jan 31, 2016 - * Author: bush */ @@ -21,12 +21,9 @@ void fill_message_type(void* buffer, MSG_TYPE type) memcpy(buffer, &type, sizeof(MSG_TYPE)); } -void fill_message_type(vector& buffer, MSG_TYPE type) +void fill_message_type(SendBuffer& buffer, MSG_TYPE type) { - // compatibility - buffer.resize(buffer.size() + 4); - char* start = (char*)&type; - copy(start, start + sizeof(MSG_TYPE), buffer.end() - 4); + buffer.serialize(type); } diff --git a/BMR/proto_utils.h b/BMR/proto_utils.h index 952e12b5..6d321fbb 100644 --- a/BMR/proto_utils.h +++ b/BMR/proto_utils.h @@ -1,8 +1,8 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + /* * utils.h * - * Created on: Jan 31, 2016 - * Author: bush */ #ifndef PROTO_UTILS_H_ @@ -11,23 +11,30 @@ #include "msg_types.h" #include #include +#include +#include +using namespace std; + +#include "Tools/avx_memcpy.h" +#include "Tools/FlexBuffer.h" #define LOOPBACK_STR "LOOPBACK" void fill_random(void* buffer, unsigned int length); -void fill_message_type(void* buffer, MSG_TYPE type); +class SendBuffer; -char cs(char* msg, unsigned int len, char result=0); +void fill_message_type(void* buffer, MSG_TYPE type); +void fill_message_type(SendBuffer& buffer, MSG_TYPE type); void phex (const void *addr, int len); //inline void xor_big(const char* input1, const char* input2, char* output); -inline timeval* GET_TIME() { - struct timeval* now = new struct timeval(); - int rc = gettimeofday(now, 0); +inline timeval GET_TIME() { + struct timeval now; + int rc = gettimeofday(&now, 0); if (rc != 0) { perror("gettimeofday"); } @@ -46,6 +53,29 @@ inline unsigned long PRINT_DIFF(struct timeval* before, struct timeval* after) { return diff; } +inline void phex(const FlexBuffer& buffer) { phex(buffer.data(), buffer.size()); } +inline void print_bit_array(const char* bits, int len) +{ + for (int i = 0; i < len; i++) + { + if (i % 8 == 0) + cout << " "; + cout << (int)bits[i]; + } + cout << endl; +} + +inline void print_bit_array(const vector& bits) +{ + print_bit_array(bits.data(), bits.size()); +} + +inline void print_indices(const vector& indices) +{ + for (unsigned i = 0; i < indices.size(); i++) + cout << indices[i] << " "; + cout << endl; +} #endif /* NETWORK_TEST_UTILS_H_ */ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 46fb0d85..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,62 +0,0 @@ -The changelog explains changes pulled through from the private development repository. Bug fixes and small enchancements are committed between releases and not documented here. - -## 0.0.3 (Mar 2, 2018) - -- Added offline phases based on homomorphic encryption, used in the [SPDZ-2 paper](https://eprint.iacr.org/2012/642) and the [Overdrive paper](https://eprint.iacr.org/2017/1230). -- On macOS, the minimum requirement is now Sierra. -- Compilation with LLVM/clang is now possible (tested with 3.8). - -## 0.0.2 (Sep 13, 2017) - -### Support sockets based external client input and output to a SPDZ MPC program. - -See the [ExternalIO directory](./ExternalIO/README.md) for more details and examples. - -Note that [libsodium](https://download.libsodium.org/doc/) is now a dependency on the SPDZ build. - -Added compiler instructions: - -* LISTEN -* ACCEPTCLIENTCONNECTION -* CONNECTIPV4 -* WRITESOCKETSHARE -* WRITESOCKETINT - -Removed instructions: - -* OPENSOCKET -* CLOSESOCKET - -Modified instructions: - -* READSOCKETC -* READSOCKETS -* READSOCKETINT -* WRITESOCKETC -* WRITESOCKETS - -Support secure external client input and output with new instructions: - -* READCLIENTPUBLICKEY -* INITSECURESOCKET -* RESPSECURESOCKET - -### Read/Write secret shares to disk to support persistence in a SPDZ MPC program. - -Added compiler instructions: - -* READFILESHARE -* WRITEFILESHARE - -### Other instructions - -Added compiler instructions: - -* DIGESTC - Clear truncated hash computation -* PRINTINT - Print register value - -## 0.0.1 (Sep 2, 2016) - -### Initial Release - -* See `README.md` and `tutorial.md`. diff --git a/CONFIG b/CONFIG index 607c26a7..7cc1a5e3 100644 --- a/CONFIG +++ b/CONFIG @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt ROOT = . @@ -17,6 +17,10 @@ USE_GF2N_LONG = 0 # AVX2 support (Haswell or later) changes the bit matrix transpose ARCH = -mtune=native -mavx +# defaults for BMR, change number of parties here +CFLAGS = -DN_PARTIES=2 -DFREE_XOR -DKEY_SIGNAL -DSPDZ_AUTH -DNO_INPUT -DMAX_INLINE +USE_GF2N_LONG = 1 + #use CONFIG.mine to overwrite DIR settings -include CONFIG.mine @@ -39,8 +43,10 @@ ifeq ($(OS), Linux) LDLIBS += -lrt endif +BOOST = -lboost_system -lboost_thread $(MY_BOOST) + CXX = g++ -CFLAGS = $(ARCH) $(MY_CFLAGS) -g -Wextra -Wall $(OPTIM) -I$(ROOT) -pthread $(PROF) $(DEBUG) $(MOD) $(MEMPROTECT) $(GF2N_LONG) $(PREP_DIR) -maes -mpclmul -msse4.1 --std=c++11 -Werror +CFLAGS += $(ARCH) $(MY_CFLAGS) -g -Wextra -Wall $(OPTIM) -I$(ROOT) -pthread $(PROF) $(DEBUG) $(MOD) $(MEMPROTECT) $(GF2N_LONG) $(PREP_DIR) -maes -mpclmul -msse4.1 --std=c++11 -Werror CPPFLAGS = $(CFLAGS) LD = g++ diff --git a/Check-Offline.cpp b/Check-Offline.cpp index 57b8dcde..8710321a 100644 --- a/Check-Offline.cpp +++ b/Check-Offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Check-Offline.cpp diff --git a/Compiler/GC/__init__.py b/Compiler/GC/__init__.py new file mode 100644 index 00000000..6e68b347 --- /dev/null +++ b/Compiler/GC/__init__.py @@ -0,0 +1,2 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + diff --git a/Compiler/GC/instructions.py b/Compiler/GC/instructions.py new file mode 100644 index 00000000..c7992501 --- /dev/null +++ b/Compiler/GC/instructions.py @@ -0,0 +1,166 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +import Compiler.instructions_base as base +import Compiler.instructions as spdz +import Compiler.tools as tools +import collections +import itertools + +class SecretBitsAF(base.RegisterArgFormat): + reg_type = 'sb' +class ClearBitsAF(base.RegisterArgFormat): + reg_type = 'cb' + +base.ArgFormats['sb'] = SecretBitsAF +base.ArgFormats['sbw'] = SecretBitsAF +base.ArgFormats['cb'] = ClearBitsAF +base.ArgFormats['cbw'] = ClearBitsAF + +opcodes = dict( + XORS = 0x200, + XORM = 0x201, + ANDRS = 0x202, + BITDECS = 0x203, + BITCOMS = 0x204, + CONVSINT = 0x205, + LDMSDI = 0x206, + STMSDI = 0x207, + LDMSD = 0x208, + STMSD = 0x209, + LDBITS = 0x20a, + XORCI = 0x210, + BITDECC = 0x211, + CONVCINT = 0x213, + REVEAL = 0x214, + STMSDCI = 0x215, +) + +class xors(base.Instruction): + code = opcodes['XORS'] + arg_format = tools.cycle(['int','sbw','sb','sb']) + +class xorm(base.Instruction): + code = opcodes['XORM'] + arg_format = ['int','sbw','sb','cb'] + +class xorc(base.Instruction): + code = base.opcodes['XORC'] + arg_format = ['cbw','cb','cb'] + +class xorci(base.Instruction): + code = opcodes['XORCI'] + arg_format = ['cbw','cb','int'] + +class andrs(base.Instruction): + code = opcodes['ANDRS'] + arg_format = tools.cycle(['int','sbw','sb','sb']) + +class addc(base.Instruction): + code = base.opcodes['ADDC'] + arg_format = ['cbw','cb','cb'] + +class addci(base.Instruction): + code = base.opcodes['ADDCI'] + arg_format = ['cbw','cb','int'] + +class mulci(base.Instruction): + code = base.opcodes['MULCI'] + arg_format = ['cbw','cb','int'] + +class bitdecs(base.VarArgsInstruction): + code = opcodes['BITDECS'] + arg_format = tools.chain(['sb'], itertools.repeat('sbw')) + +class bitcoms(base.VarArgsInstruction): + code = opcodes['BITCOMS'] + arg_format = tools.chain(['sbw'], itertools.repeat('sb')) + +class bitdecc(base.VarArgsInstruction): + code = opcodes['BITDECC'] + arg_format = tools.chain(['cb'], itertools.repeat('cbw')) + +class shrci(base.Instruction): + code = base.opcodes['SHRCI'] + arg_format = ['cbw','cb','int'] + +class ldbits(base.Instruction): + code = opcodes['LDBITS'] + arg_format = ['sbw','i','i'] + +class ldms(base.DirectMemoryInstruction, base.ReadMemoryInstruction): + code = base.opcodes['LDMS'] + arg_format = ['sbw','int'] + +class stms(base.DirectMemoryWriteInstruction): + code = base.opcodes['STMS'] + arg_format = ['sb','int'] + # def __init__(self, *args, **kwargs): + # super(type(self), self).__init__(*args, **kwargs) + # import inspect + # self.caller = [frame[1:] for frame in inspect.stack()[1:]] + +class ldmc(base.DirectMemoryInstruction, base.ReadMemoryInstruction): + code = base.opcodes['LDMC'] + arg_format = ['cbw','int'] + +class stmc(base.DirectMemoryWriteInstruction): + code = base.opcodes['STMC'] + arg_format = ['cb','int'] + +class ldmsi(base.ReadMemoryInstruction): + code = base.opcodes['LDMSI'] + arg_format = ['sbw','ci'] + +class stmsi(base.WriteMemoryInstruction): + code = base.opcodes['STMSI'] + arg_format = ['sb','ci'] + +class ldmsdi(base.ReadMemoryInstruction): + code = opcodes['LDMSDI'] + arg_format = tools.cycle(['sbw','cb','int']) + +class stmsdi(base.WriteMemoryInstruction): + code = opcodes['STMSDI'] + arg_format = tools.cycle(['sb','cb']) + +class ldmsd(base.ReadMemoryInstruction): + code = opcodes['LDMSD'] + arg_format = tools.cycle(['sbw','int','int']) + +class stmsd(base.WriteMemoryInstruction): + code = opcodes['STMSD'] + arg_format = tools.cycle(['sb','int']) + +class stmsdci(base.WriteMemoryInstruction): + code = opcodes['STMSDCI'] + arg_format = tools.cycle(['cb','cb']) + +class convsint(base.Instruction): + code = opcodes['CONVSINT'] + arg_format = ['int','sbw','ci'] + +class convcint(base.Instruction): + code = opcodes['CONVCINT'] + arg_format = ['cbw','ci'] + +class movs(base.Instruction): + code = base.opcodes['MOVS'] + arg_format = ['sbw','sb'] + +class bit(base.Instruction): + code = base.opcodes['BIT'] + arg_format = ['sbw'] + +class reveal(base.Instruction): + code = opcodes['REVEAL'] + arg_format = ['int','cbw','sb'] + +class print_reg(base.IOInstruction): + code = base.opcodes['PRINTREG'] + arg_format = ['cb','i'] + def __init__(self, reg, comment=''): + super(print_reg, self).__init__(reg, self.str_to_int(comment)) + +class print_reg_plain(base.IOInstruction): + code = base.opcodes['PRINTREGPLAIN'] + arg_format = ['cb'] diff --git a/Compiler/GC/program.py b/Compiler/GC/program.py new file mode 100644 index 00000000..da386f43 --- /dev/null +++ b/Compiler/GC/program.py @@ -0,0 +1,12 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +from Compiler import types, instructions + +class Program(object): + def __init__(self, progname): + types.program = self + instructions.program = self + self.curr_tape = None + execfile(progname) + def malloc(self, *args): + pass diff --git a/Compiler/GC/types.py b/Compiler/GC/types.py new file mode 100644 index 00000000..0eddb2f5 --- /dev/null +++ b/Compiler/GC/types.py @@ -0,0 +1,352 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +from Compiler.types import MemValue, read_mem_value, regint, Array +from Compiler.program import Tape, Program +from Compiler.exceptions import * +from Compiler import util, oram, floatingpoint +import Compiler.GC.instructions as inst +import operator + +class bits(Tape.Register): + n = 40 + size = 1 + PreOp = staticmethod(floatingpoint.PreOpN) + MemValue = staticmethod(lambda value: MemValue(value)) + @staticmethod + def PreOR(l): + return [1 - x for x in \ + floatingpoint.PreOpN(operator.mul, \ + [1 - x for x in l])] + @classmethod + def get_type(cls, length): + if length is None: + return cls + elif length == 1: + return cls.bit_type + if length not in cls.types: + class bitsn(cls): + n = length + cls.types[length] = bitsn + bitsn.__name__ = cls.__name__ + str(length) + return cls.types[length] + @classmethod + def conv(cls, other): + if isinstance(other, cls): + return other + elif isinstance(other, MemValue): + return cls.conv(other.read()) + else: + res = cls() + res.load_other(other) + return res + hard_conv = conv + @classmethod + def compose(cls, items, bit_length): + return cls.bit_compose(sum([item.bit_decompose(bit_length) for item in items], [])) + @classmethod + def bit_compose(cls, bits): + if len(bits) == 1: + return bits[0] + bits = list(bits) + res = cls.new(n=len(bits)) + cls.bitcom(res, *bits) + res.decomposed = bits + return res + def bit_decompose(self, bit_length=None): + n = bit_length or self.n + if n > self.n: + raise Exception('wanted %d bits, only got %d' % (n, self.n)) + if n == 1: + return [self] + if self.decomposed is None or len(self.decomposed) < n: + res = [self.bit_type() for i in range(n)] + self.bitdec(self, *res) + self.decomposed = res + return res + else: + return self.decomposed[:n] + @classmethod + def load_mem(cls, address, mem_type=None): + res = cls() + if mem_type == 'sd': + return cls.load_dynamic_mem(address) + else: + cls.load_inst[util.is_constant(address)](res, address) + return res + def store_in_mem(self, address): + self.store_inst[isinstance(address, (int, long))](self, address) + def __init__(self, value=None, n=None): + Tape.Register.__init__(self, self.reg_type, Program.prog.curr_tape) + self.set_length(n or self.n) + if value is not None: + self.load_other(value) + self.decomposed = None + def set_length(self, n): + if n > self.max_length: + print self.max_length + raise Exception('too long: %d' % n) + self.n = n + def load_other(self, other): + if isinstance(other, (int, long)): + self.set_length(self.n or util.int_len(other)) + self.load_int(other) + elif isinstance(other, regint): + self.conv_regint(self.n, self, other) + elif isinstance(self, type(other)) or isinstance(other, type(self)): + self.mov(self, other) + else: + raise CompilerError('cannot convert from %s to %s' % \ + (type(other), type(self))) + def __repr__(self): + return '%s(%d/%d)' % \ + (super(bits, self).__repr__(), self.n, type(self).n) + +class cbits(bits): + max_length = 64 + reg_type = 'cb' + is_clear = True + load_inst = (None, inst.ldmc) + store_inst = (None, inst.stmc) + bitdec = inst.bitdecc + conv_regint = staticmethod(lambda n, x, y: inst.convcint(x, y)) + types = {} + def load_int(self, value): + self.load_other(regint(value)) + def store_in_dynamic_mem(self, address): + inst.stmsdci(self, cbits.conv(address)) + def clear_op(self, other, c_inst, ci_inst, op): + if isinstance(other, cbits): + res = cbits(n=max(self.n, other.n)) + c_inst(res, self, other) + return res + else: + if util.is_constant(other): + if other >= 2**31 or other < -2**31: + return op(self, cbits(other)) + res = cbits(n=max(self.n, len(bin(other)) - 2)) + ci_inst(res, self, other) + return res + else: + return op(self, cbits(other)) + __add__ = lambda self, other: \ + self.clear_op(other, inst.addc, inst.addci, operator.add) + __xor__ = lambda self, other: \ + self.clear_op(other, inst.xorc, inst.xorci, operator.xor) + __radd__ = __add__ + __rxor__ = __xor__ + def __mul__(self, other): + if isinstance(other, cbits): + return NotImplemented + else: + try: + res = cbits(n=min(self.max_length, self.n+util.int_len(other))) + inst.mulci(res, self, other) + return res + except TypeError: + return NotImplemented + def __rshift__(self, other): + res = cbits(n=self.n-other) + inst.shrci(res, self, other) + return res + def print_reg(self, desc=''): + inst.print_reg(self, desc) + def print_reg_plain(self): + inst.print_reg_plain(self) + output = print_reg_plain + def reveal(self): + return self + +class sbits(bits): + max_length = 128 + reg_type = 'sb' + is_clear = False + clear_type = cbits + default_type = cbits + load_inst = (inst.ldmsi, inst.ldms) + store_inst = (inst.stmsi, inst.stms) + bitdec = inst.bitdecs + bitcom = inst.bitcoms + conv_regint = inst.convsint + mov = inst.movs + types = {} + def __init__(self, *args, **kwargs): + bits.__init__(self, *args, **kwargs) + @staticmethod + def new(value=None, n=None): + if n == 1: + return sbit(value) + else: + return sbits.get_type(n)(value) + @staticmethod + def get_random_bit(): + res = sbit() + inst.bit(res) + return res + @classmethod + def load_dynamic_mem(cls, address): + res = cls() + if isinstance(address, (long, int)): + inst.ldmsd(res, address, cls.n) + else: + inst.ldmsdi(res, address, cls.n) + return res + def store_in_dynamic_mem(self, address): + if isinstance(address, (long, int)): + inst.stmsd(self, address) + else: + inst.stmsdi(self, cbits.conv(address)) + def load_int(self, value): + if abs(value) < 2**31: + if (abs(value) > (1 << self.n)): + raise Exception('public value %d longer than %d bits' \ + % (value, self.n)) + inst.ldbits(self, self.n, value) + else: + value %= 2**self.n + if value >> 64 != 0: + raise NotImplementedError('public value too large') + self.load_other(regint(value)) + @read_mem_value + def __add__(self, other): + if isinstance(other, int): + return self.xor_int(other) + else: + if not isinstance(other, sbits): + other = sbits(other) + n = self.n + else: + n = max(self.n, other.n) + res = self.new(n=n) + inst.xors(n, res, self, other) + return res + __radd__ = __add__ + __sub__ = __add__ + __xor__ = __add__ + __rxor__ = __add__ + @read_mem_value + def __rsub__(self, other): + if isinstance(other, cbits): + return other + self + else: + return self.xor_int(other) + @read_mem_value + def __mul__(self, other): + if isinstance(other, int): + return self.mul_int(other) + try: + if min(self.n, other.n) != 1: + raise NotImplementedError('high order multiplication') + n = max(self.n, other.n) + res = self.new(n=max(self.n, other.n)) + order = (self, other) if self.n != 1 else (other, self) + inst.andrs(n, res, *order) + return res + except AttributeError: + return NotImplemented + @read_mem_value + def __rmul__(self, other): + if isinstance(other, cbits): + return other * self + else: + return self.mul_int(other) + def xor_int(self, other): + if other == 0: + return self + self_bits = self.bit_decompose() + other_bits = util.bit_decompose(other, max(self.n, util.int_len(other))) + extra_bits = [self.new(b, n=1) for b in other_bits[self.n:]] + return self.bit_compose([~x if y else x \ + for x,y in zip(self_bits, other_bits)] \ + + extra_bits) + def mul_int(self, other): + if other == 0: + return 0 + elif other == 1: + return self + elif self.n == 1: + bits = util.bit_decompose(other, util.int_len(other)) + zero = sbit(0) + mul_bits = [self if b else zero for b in bits] + return self.bit_compose(mul_bits) + else: + print self.n, other + return NotImplemented + def __lshift__(self, i): + return self.bit_compose([sbit(0)] * i + self.bit_decompose()[:self.max_length-i]) + def __invert__(self): + # res = type(self)(n=self.n) + # inst.nots(res, self) + # return res + one = self.new(value=1, n=1) + bits = [one + bit for bit in self.bit_decompose()] + return self.bit_compose(bits) + def __neg__(self): + return self + def reveal(self): + if self.n > self.clear_type.max_length: + raise Exception('too long to reveal') + res = self.clear_type(n=self.n) + inst.reveal(self.n, res, self) + return res + def equal(self, other, n=None): + bits = (~(self + other)).bit_decompose() + return reduce(operator.mul, bits) + +class bit(object): + n = 1 + +class sbit(bit, sbits): + def if_else(self, x, y): + return self * (x ^ y) ^ y + +class cbit(bit, cbits): + pass + +sbits.bit_type = sbit +cbits.bit_type = cbit + +class bitsBlock(oram.Block): + value_type = sbits + def __init__(self, value, start, lengths, entries_per_block): + oram.Block.__init__(self, value, lengths) + length = sum(self.lengths) + used_bits = entries_per_block * length + self.value_bits = self.value.bit_decompose(used_bits) + start_length = util.log2(entries_per_block) + self.start_bits = util.bit_decompose(start, start_length) + self.start_demux = oram.demux_list(self.start_bits) + self.entries = [sbits.bit_compose(self.value_bits[i*length:][:length]) \ + for i in range(entries_per_block)] + self.mul_entries = map(operator.mul, self.start_demux, self.entries) + self.bits = sum(self.mul_entries).bit_decompose() + self.mul_value = sbits.compose(self.mul_entries, sum(self.lengths)) + self.anti_value = self.mul_value + self.value + def set_slice(self, value): + value = sbits.compose(util.tuplify(value), sum(self.lengths)) + for i,b in enumerate(self.start_bits): + value = b.if_else(value << (2**i * sum(self.lengths)), value) + self.value = value + self.anti_value + return self + +oram.block_types[sbits] = bitsBlock + +class dyn_sbits(sbits): + pass + +class DynamicArray(Array): + def __init__(self, *args): + Array.__init__(self, *args) + def _malloc(self): + return Program.prog.malloc(self.length, 'sd', self.value_type) + def _load(self, address): + return self.value_type.load_dynamic_mem(cbits.conv(address)) + def _store(self, value, address): + if isinstance(value, MemValue): + value = value.read() + if isinstance(value, sbits): + self.value_type.conv(value).store_in_dynamic_mem(address) + else: + cbits.conv(value).store_in_dynamic_mem(address) + +sbits.dynamic_array = DynamicArray +cbits.dynamic_array = Array diff --git a/Compiler/__init__.py b/Compiler/__init__.py index 33338e9f..145ad2aa 100644 --- a/Compiler/__init__.py +++ b/Compiler/__init__.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import compilerLib, program, instructions, types, library, floatingpoint import inspect diff --git a/Compiler/allocator.py b/Compiler/allocator.py index 9e4471c5..96163a5a 100644 --- a/Compiler/allocator.py +++ b/Compiler/allocator.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import itertools, time from collections import defaultdict, deque @@ -151,7 +151,7 @@ def determine_scope(block, options): block.defined_registers = set(last_def.iterkeys()) class Merger: - def __init__(self, block, options): + def __init__(self, block, options, merge_classes, stop_class=stopopen_class): self.block = block self.instructions = block.instructions self.options = options @@ -159,7 +159,7 @@ class Merger: self.max_parallel_open = int(options.max_parallel_open) else: self.max_parallel_open = float('inf') - self.dependency_graph() + self.dependency_graph(merge_classes, stop_class) def do_merge(self, merges_iter): """ Merge an iterable of nodes in G, returning the number of merged @@ -341,8 +341,7 @@ class Merger: preorder.extend(reversed(startinputs)) return preorder - def longest_paths_merge(self, instruction_type=startopen_class, - merge_stopopens=True): + def longest_paths_merge(self, merge_stopopens=True): """ Attempt to merge instructions of type instruction_type (which are given in merge_nodes) using longest paths algorithm. @@ -357,8 +356,6 @@ class Merger: instructions = self.instructions merge_nodes = self.open_nodes depths = self.depths - if instruction_type is not startopen_class and merge_stopopens: - raise CompilerError('Cannot merge stopopens whilst merging %s instructions' % instruction_type) if not merge_nodes and not self.input_nodes: return 0 @@ -379,8 +376,7 @@ class Merger: my_merge = (m for m in merge if instructions[m] is not None and instructions[m].is_gf2n() is b) if merge_stopopens: - my_stopopen = [G.get_attr(m, 'stop') for m in merge if instructions[m] is not None and instructions[m].is_gf2n() is b] - + my_stopopen = filter(lambda x: x != -1, (G.get_attr(m, 'stop') for m in merge if instructions[m] is not None and instructions[m].is_gf2n() is b)) mc, nodes[0,b] = self.do_merge(iter(my_merge)) if merge_stopopens: @@ -420,8 +416,16 @@ class Merger: return len(merges) - def dependency_graph(self, merge_class=startopen_class): + def dependency_graph(self, merge_classes, stop_class): """ Create the program dependency graph. """ + if len(merge_classes) != 1: + if stop_class is not type(None): + raise NotImplementedError('stop merging only implemented ' \ + 'for single instruction') + if int(self.options.max_parallel_open): + raise NotImplementedError('parallel limit only implemented ' \ + 'for single instruction') + block = self.block options = self.options open_nodes = set() @@ -453,13 +457,10 @@ class Merger: next_available_depth = {} self.sources = [] self.real_depths = [0] * len(block.instructions) + round_type = {} def add_edge(i, j): - from_merge = isinstance(block.instructions[i], merge_class) - to_merge = isinstance(block.instructions[j], merge_class) G.add_edge(i, j) - is_source = G.get_attr(i, 'is_source') and G.get_attr(j, 'is_source') and not from_merge - G.set_attr(j, 'is_source', is_source) for d in (self.depths, self.real_depths): if d[j] < d[i]: d[j] = d[i] @@ -515,7 +516,7 @@ class Merger: for n,instr in enumerate(block.instructions): outputs,inputs = instr.get_def(), instr.get_used() - G.add_node(n, is_source=True) + G.add_node(n) # if options.debug: # col = colordict[instr.__class__.__name__] @@ -534,13 +535,19 @@ class Merger: else: write(reg, n) - if isinstance(instr, merge_class): + if isinstance(instr, merge_classes): open_nodes.add(n) - last_open.append(n) G.add_node(n, merges=[]) + if stop_class != type(None): + last_open.append(n) # the following must happen after adding the edge self.real_depths[n] += 1 depth = depths[n] + 1 + while depth in round_type: + if round_type[depth] == type(instr): + break + depth += 1 + round_type[depth] = type(instr) if int(options.max_parallel_open): skipped_depths = set() while parallel_open[depth] >= int(options.max_parallel_open): @@ -548,10 +555,12 @@ class Merger: depth = next_available_depth.get(depth, depth + 1) for d in skipped_depths: next_available_depth[d] = depth + else: + self.real_depths[n] = depth parallel_open[depth] += len(instr.args) * instr.get_size() depths[n] = depth - if isinstance(instr, stopopen_class): + if isinstance(instr, stop_class): startopen = last_open.popleft() add_edge(startopen, n) G.set_attr(startopen, 'stop', n) @@ -609,7 +618,7 @@ class Merger: (n, len(block.instructions)), time.asctime() if len(open_nodes) > 1000: - print "Program has %d %s instructions" % (len(open_nodes), merge_class) + print "Program has %d %s instructions" % (len(open_nodes), merge_classes) def merge_nodes(self, i, j): """ Merge node j into i, removing node j """ diff --git a/Compiler/circuit_oram.py b/Compiler/circuit_oram.py new file mode 100644 index 00000000..04166fbd --- /dev/null +++ b/Compiler/circuit_oram.py @@ -0,0 +1,295 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + + +from Compiler.path_oram import * +from Compiler.util import bit_compose + +def first_diff(a_bits, b_bits): + length = len(a_bits) + level_bits = [None] * length + not_found = 1 + for i in range(length): + # find first position where bits differ (i.e. first 0 in 1 - a XOR b) + t = 1 - XOR(a_bits[i], b_bits[i]) + prev_nf = not_found + not_found *= t + level_bits[i] = prev_nf - not_found + return level_bits, not_found + +def find_deeper(a, b, path, start, length, compute_level=True): + a_bits = a.value.bit_decompose(length) + b_bits = b.value.bit_decompose(length) + path_bits = [type(a_bits[0])(x) for x in path.bit_decompose(length)] + a_bits.reverse() + b_bits.reverse() + path_bits.reverse() + level_bits = [0] * length + # make sure that winner is set at start if one input is empty + any_empty = OR(a.empty, b.empty) + a_diff = [XOR(a_bits[i], path_bits[i]) for i in range(start, length)] + b_diff = [XOR(b_bits[i], path_bits[i]) for i in range(start, length)] + diff = [XOR(ab, bb) for ab,bb in zip(a_bits, b_bits)[start:length]] + diff_preor = type(a.value).PreOR([any_empty] + diff) + diff_first = [x - y for x,y in zip(diff_preor, diff_preor[1:])] + winner = sum((ad * df for ad,df in zip(a_diff, diff_first)), a.empty) + winner_bits = [if_else(winner, bd, ad) for ad,bd in zip(a_diff, b_diff)] + winner_preor = type(a.value).PreOR(winner_bits) + level_bits = [x - y for x,y in zip(winner_preor, [0] + winner_preor)] + return [0] * start + level_bits + [1 - sum(level_bits)], winner + +def find_deepest(paths, search_path, start, length, compute_level=True): + if len(paths) == 1: + return None, paths[0], 1 + l = len(paths) / 2 + _, a, a_index = find_deepest(paths[:l], search_path, start, length, False) + _, b, b_index = find_deepest(paths[l:], search_path, start, length, False) + level, winner = find_deeper(a, b, search_path, start, length, compute_level) + return level, if_else(winner, b, a), if_else(winner, b_index << l, a_index) + +def ge_unary_public(a, b): + return sum(a[b-1:]) + +def gu_step(high, low): + greater = high[0] * (1 - high[1]) + not_greater = high[1] + return if_else(not_greater, 0, high[0] + low[0]), \ + if_else(greater, 0, high[1] + low[1]) + +def greater_unary(a, b): + if len(a) == 1: + return a[0], b[0] + else: + l = len(a) / 2 + return gu_step(greater_unary(a[l:], b[l:]), greater_unary(a[:l], b[:l])) + +def comp_step(high, low): + prod = high[0] * high[1] + greater = high[0] - prod + smaller = high[1] - prod + deferred = 1 - greater - smaller + indicator = greater, smaller, deferred + return sum(map(operator.mul, indicator, (1, 0, low[0]))), \ + sum(map(operator.mul, indicator, (0, 1, low[1]))) + +def comp_binary(a, b): + if len(a) != len(b): + raise CompilerError('Arguments must have same length: %s %s' % (str(a), str(b))) + if len(a) == 1: + return a[0], b[0] + else: + l = len(a) / 2 + return comp_step(comp_binary(a[l:], b[l:]), comp_binary(a[:l], b[:l])) + +def unary_to_binary(l): + return sum(x * (i + 1) for i,x in enumerate(l)).bit_decompose(log2(len(l) + 1)) + +class CircuitORAM(PathORAM): + def __init__(self, size, value_type=sgf2n, value_length=1, entry_size=None, \ + stash_size=None, bucket_size=2, init_rounds=-1): + self.bucket_oram = TrivialORAM + self.bucket_size = bucket_size + self.D = log2(size) + self.logD = log2(self.D) + self.L = self.D + 1 + print 'create oram of size %d with depth %d and %d buckets' \ + % (size, self.D, self.n_buckets()) + self.value_type = value_type + self.index_type = value_type.get_type(self.D) + if entry_size is not None: + self.value_length = len(tuplify(entry_size)) + self.entry_size = tuplify(entry_size) + else: + self.value_length = value_length + self.entry_size = [None] * value_length + self.index_size = log2(size) + self.size = size + empty_entry = Entry.get_empty(*self.internal_entry_size(), \ + index_size=self.index_size) + self.entry_type = empty_entry.types() + self.ram = RAM(self.bucket_size * 2**(self.D+1), self.entry_type, \ + self.get_array) + self.buckets = self.ram + if init_rounds != -1: + # put memory initialization in different timer + stop_timer() + start_timer(1) + self.ram.init_mem(self.empty_entry(apply_type=False)) + if init_rounds != -1: + stop_timer(1) + start_timer() + self.root = RefBucket(1, self) + self.index = self.index_structure(size, self.D, value_type, init_rounds, True) + stash_size = 20 + vt, es = self.internal_entry_size() + self.stash = TrivialORAM(stash_size, vt, entry_size=es, \ + index_size=self.index_size) + self.t = MemValue(regint(0)) + self.state = MemValue(self.value_type.get_type(self.D)(0)) + self.read_path = MemValue(value_type.clear_type(0)) + # these include a read value from the stash + self.read_value = [Array(self.D + 2, self.value_type.get_type(l)) + for l in self.entry_size] + self.read_empty = Array(self.D + 2, self.value_type.bit_type) + def get_ram_index(self, path, level): + clear_type = self.value_type.clear_type + return ((2**(self.D) + clear_type.conv(path)) >> (self.D - (level - 1))) + def get_bucket_ram(self, path, level): + if level == 0: + return self.stash.ram + else: + return RefRAM(self.get_ram_index(path, level), self) + def get_bucket_oram(self, path, level): + if level == 0: + return self.stash + else: + return RefTrivialORAM(self.get_ram_index(path, level), self) + def prepare_deepest(self, path): + deepest = [None] * (self.D + 2) + deepest_index = [None] * (self.D + 2) + src = Value() + stash_empty = self.stash.ram.is_empty() + level, _, index = find_deepest(self.stash.ram.get_value_array(0), path, 0, self.D) + goal = if_else(stash_empty, ValueTuple([0] * len(level)), unary_to_binary(level)) + src = if_else(stash_empty, src, Value(0)) + src_index = if_else(stash_empty, 0, index) + buckets = [self.get_bucket_ram(path, i) for i in range(self.L + 1)] + bucket_deepest = [(goal, src, src_index, None)] + for i in range(1, self.L): + l, _, index = find_deepest(buckets[i].get_value_array(0), path, i - 1, self.D) + bucket_deepest.append((unary_to_binary(l), Value(i), index, i)) + def op(left, right, void=None): + goal, src, src_index, _ = left + l, secret_i, index, i = right + high, low = comp_binary(l, goal) + replace = high * (1 - low) * (1 - buckets[i].is_empty()) + goal = if_else(replace, bit_compose(l), \ + bit_compose(goal)).bit_decompose(len(goal)) + src = if_else(replace, secret_i, src) + src_index = if_else(replace, index, src_index) + return goal, src, src_index, i + preop_bucket_deepest = self.value_type.PreOp(op, bucket_deepest) + for i in range(1, self.L + 1): + goal, src, src_index, _ = preop_bucket_deepest[i-1] + high, low = comp_binary(goal, bit_decompose(i, len(goal))) + cond = 1 - low * (1 - high) + deepest[i] = if_else(cond, src, Value()) + deepest_index[i] = if_else(cond, src_index, 0) + return deepest, deepest_index + def prepare_target(self, path, deepest): + deepest, deepest_index = deepest + dest = Value() + src = Value() + src_index = 0 + target = [None] * (self.L + 1) + target_index = [None] * (self.L + 1) + for i in range(self.L, -1 , -1): + i_eq_src = src.equal(i, self.logD + 1) + target[i] = if_else(i_eq_src, dest, Value()) + target_index[i] = if_else(i_eq_src, src_index, 0) + dest = if_else(i_eq_src, Value(), dest) + src = if_else(i_eq_src, Value(), src) + if i == 0: + break + cond = or_op(dest.empty * self.get_bucket_ram(path, i).has_empty_entry(), \ + (1 - target[i].empty)) * (1 - deepest[i].empty) + src = if_else(cond, deepest[i], src) + src_index = if_else(cond, deepest_index[i], src_index) + dest = if_else(cond, Value(i), dest) + return target, target_index + def evict_once(self, path): + deepest = self.prepare_deepest(path) + target = self.prepare_target(path, deepest) + evictor = self.evict_once_fast(path, target) + next(evictor) + towrite = next(evictor) + yield + self.add_evicted(path, towrite) + yield + def evict_once_fast(self, path, target): + target, target_index = target + empty_entry = Entry.get_empty(*self.internal_entry_size(), \ + index_size=self.index_size) + hold = empty_entry + dest = Value() + towrite = [None] * (self.L + 1) + for i in range(self.L + 1): + cond = (1 - hold.is_empty) * (dest.equal(i, self.logD + 1)) + towrite[i] = if_else(cond, hold, empty_entry) + hold = if_else(cond, empty_entry, hold) + dest = if_else(cond, Value(), dest) + cond = 1 - target[i].empty + bucket = self.get_bucket_oram(path, i) + if i != self.L: + index = target_index[i].bit_decompose(bucket.size) + hold = if_else(cond, bucket.read_and_remove_by_public(index), hold) + dest = if_else(cond, target[i], dest) + if i == 1: + yield + yield towrite + def add_evicted(self, path, towrite): + # make sure to add after removing + for i in range(1, self.L + 1): + self.get_bucket_oram(path, i).add(towrite[i]) + def evict_rounds(self): + get_path = lambda x: bit_compose(reversed(x.bit_decompose(self.D))) + paths = [get_path(2 * self.t + i) for i in range(2)] + for path in paths: + for _ in self.evict_once(path): + yield + self.t.iadd(1) + def evict(self): + raise CompilerException('Using this function is likely an error. Use recursive_evict() instead.') + Program.prog.curr_tape.start_new_basicblock(name='circuit-evict-%d' % self.size) + for i,_ in enumerate(self.evict_rounds()): + Program.prog.curr_tape.start_new_basicblock(name='circuit-evict-round-%d-%d' % (i, self.size)) + def recursive_evict(self): + Program.prog.curr_tape.start_new_basicblock(name='circuit-recursive-evict-%d' % self.size) + for i,_ in enumerate(self.recursive_evict_rounds()): + Program.prog.curr_tape.start_new_basicblock(name='circuit-recursive-evict-round-%d-%d' % (i, self.size)) + def recursive_evict_rounds(self): + for _ in itertools.izip(self.evict_rounds(), self.index.l.recursive_evict_rounds()): + yield + def bucket_indices_on_path_to(self, leaf): + # root is at 1, different to PathORAM + for level in range(self.D + 1): + base = self.get_ram_index(leaf, level + 1) * self.bucket_size + yield [base + i for i in range(self.bucket_size)] + def output(self): + print_ln('stash') + self.stash.output() + @for_range(1, 2**(self.D+1)) + def f(i): + print_ln('node %s', self.value_type.clear_type(i)) + RefRAM(i, self).output() + self.index.output() + def __repr__(self): + return repr(self.stash) + '\n' + repr(RefBucket(1, self)) + +class DebugCircuitORAM(CircuitORAM): + """ Debugging only. Tree ORAM using index revealing the access + pattern. """ + index_structure = LocalIndexStructure + +threshold = 2**10 + +def OptimalCircuitORAM(size, value_type, *args, **kwargs): + if size <= threshold: + print size, 'below threshold', threshold + return LinearORAM(size, value_type, *args, **kwargs) + else: + print size, 'above threshold', threshold + return RecursiveCircuitORAM(size, value_type, *args, **kwargs) + +class RecursiveCircuitIndexStructure(PackedIndexStructure): + """ Secure index using secure tree ORAM. """ + storage = staticmethod(OptimalCircuitORAM) + +class RecursiveCircuitORAM(CircuitORAM): + """ Secure tree ORAM using secure index. """ + index_structure = RecursiveCircuitIndexStructure + +class AtLeastOneRecursionPackedCircuitORAM(PackedIndexStructure): + storage = RecursiveCircuitORAM + +class AtLeastOneRecursionPackedCircuitORAMWithEmpty(PackedORAMWithEmpty): + storage = RecursiveCircuitORAM diff --git a/Compiler/comparison.py b/Compiler/comparison.py index 6be54027..13691bd5 100644 --- a/Compiler/comparison.py +++ b/Compiler/comparison.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt """ Functions for secure comparison of GF(p) types. diff --git a/Compiler/compilerLib.py b/Compiler/compilerLib.py index ed66b492..c52ab09b 100644 --- a/Compiler/compilerLib.py +++ b/Compiler/compilerLib.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler.program import Program from Compiler.config import * diff --git a/Compiler/config.py b/Compiler/config.py index 58dff5b7..913e899c 100644 --- a/Compiler/config.py +++ b/Compiler/config.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from collections import defaultdict diff --git a/Compiler/dijkstra.py b/Compiler/dijkstra.py index b9d6b3c1..5a6ef468 100644 --- a/Compiler/dijkstra.py +++ b/Compiler/dijkstra.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler.oram import * diff --git a/Compiler/exceptions.py b/Compiler/exceptions.py index 6400ce5b..a2ce8fd4 100644 --- a/Compiler/exceptions.py +++ b/Compiler/exceptions.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt class CompilerError(Exception): """Base class for compiler exceptions.""" diff --git a/Compiler/floatingpoint.py b/Compiler/floatingpoint.py index eb80e73b..336032be 100644 --- a/Compiler/floatingpoint.py +++ b/Compiler/floatingpoint.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from math import log, floor, ceil from Compiler.instructions import * diff --git a/Compiler/graph.py b/Compiler/graph.py index 571e8b38..13759943 100644 --- a/Compiler/graph.py +++ b/Compiler/graph.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import heapq from Compiler.exceptions import * @@ -19,7 +19,7 @@ class SparseDiGraph(object): """ max_nodes: maximum no of nodes default_attributes: dict of node attributes and default values """ if default_attributes is None: - default_attributes = { 'merges': None, 'stop': -1, 'start': -1, 'is_source': True } + default_attributes = { 'merges': None, 'stop': -1, 'start': -1 } self.default_attributes = default_attributes self.attribute_pos = dict(zip(default_attributes.keys(), range(len(default_attributes)))) self.n = max_nodes diff --git a/Compiler/gs.py b/Compiler/gs.py index c6b3f52d..ca6a37f1 100644 --- a/Compiler/gs.py +++ b/Compiler/gs.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import sys import math diff --git a/Compiler/instructions.py b/Compiler/instructions.py index 857ef345..3b2f64bd 100644 --- a/Compiler/instructions.py +++ b/Compiler/instructions.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt """ This module is for classes of actual assembly instructions. @@ -335,6 +335,14 @@ class crash(base.IOInstruction): code = base.opcodes['CRASH'] arg_format = [] +class start_grind(base.IOInstruction): + code = base.opcodes['STARTGRIND'] + arg_format = [] + +class stop_grind(base.IOInstruction): + code = base.opcodes['STOPGRIND'] + arg_format = [] + @base.gf2n class use_prep(base.Instruction): r""" Input usage. """ @@ -1175,6 +1183,12 @@ class divint(base.IntegerInstruction): __slots__ = [] code = base.opcodes['DIVINT'] +@base.vectorize +class bitdecint(base.Instruction): + __slots__ = [] + code = base.opcodes['BITDECINT'] + arg_format = tools.chain(['ci'], itertools.repeat('ciw')) + ### ### Clear comparison instructions ### diff --git a/Compiler/instructions_base.py b/Compiler/instructions_base.py index d9b5e2f8..096a2a27 100644 --- a/Compiler/instructions_base.py +++ b/Compiler/instructions_base.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import itertools from random import randint @@ -54,6 +54,8 @@ opcodes = dict( JOIN_TAPE = 0x1A, CRASH = 0x1B, USE_PREP = 0x1C, + STARTGRIND = 0x1D, + STOPGRIND = 0x1E, # Addition ADDC = 0x20, ADDS = 0x21, @@ -132,6 +134,7 @@ opcodes = dict( EQC = 0x97, JMPI = 0x98, # Integers + BITDECINT = 0x99, LDINT = 0x9A, ADDINT = 0x9B, SUBINT = 0x9C, @@ -535,7 +538,11 @@ class Instruction(object): return "" def has_var_args(self): - return False + try: + len(self.arg_format) + return False + except: + return True def is_vec(self): return False diff --git a/Compiler/library.py b/Compiler/library.py index 423bf678..2c888497 100644 --- a/Compiler/library.py +++ b/Compiler/library.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler.types import cint,sint,cfix,sfix,sfloat,MPCThread,Array,MemValue,cgf2n,sgf2n,_number,_mem,_register,regint,Matrix,_types, cfloat from Compiler.instructions import * diff --git a/Compiler/oram.py b/Compiler/oram.py index c51c37d2..a8e711dd 100644 --- a/Compiler/oram.py +++ b/Compiler/oram.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import random import math @@ -187,9 +187,10 @@ def demux_list(x): res = map(operator.mul, a, b) return res -def demux_array(x): +def demux_array(x, res=None): n = len(x) - res = Array(2**n, type(x[0])) + if res is None: + res = Array(2**n, type(x[0])) if n == 1: res[0] = 1 - x[0] res[1] = x[0] @@ -282,10 +283,18 @@ class ValueTuple(tuple): class Entry(object): """ An (O)RAM entry with empty bit, index, and value. """ @staticmethod - def get_empty(value_type, value_length, apply_type=True): - t = value_type if apply_type else lambda x: x - bt = value_type if apply_type else lambda x: x - return Entry(t(0), tuple(t(0) for i in range(value_length)), bt(True), t) + def get_empty(value_type, entry_size, apply_type=True, index_size=None): + res = {} + for i,tt in enumerate((value_type, value_type.default_type)): + if apply_type: + apply = lambda length, x: value_type.get_type(length)(x) + else: + apply = lambda length, x: x + res[i] = Entry(apply(index_size, 0), \ + tuple(apply(l, 0) for l in entry_size), \ + apply(1, True), value_type) + res[0].defaults = res[1] + return res[0] def __init__(self, v, x=None, empty=None, value_type=None): self.created_non_empty = False if x is None: @@ -296,7 +305,7 @@ class Entry(object): else: if empty is None: self.created_non_empty = True - empty = value_type(False) + empty = value_type.bit_type(False) self.is_empty = empty self.v = v if not isinstance(x, (tuple, list)): @@ -360,14 +369,15 @@ class RefRAM(object): crash() self.size = oram.bucket_size self.entry_type = oram.entry_type - self.l = [t.dynamic_array(self.size, t, array.address + \ - index * oram.bucket_size) \ - for t,array in zip(self.entry_type,oram.ram.l)] + self.l = [oram.get_array(self.size, t, array.address + \ + index * oram.bucket_size) \ + for t,array in zip(self.entry_type,oram.ram.l)] self.index = index def init_mem(self, empty_entry): print 'init ram' - for a,value in zip(self.l, empty_entry.values()): - a.assign_all(value) + for a,value in zip(self.l, empty_entry.defaults.values()): + # don't use threads if n_threads explicitly set to 1 + a.assign_all(value, n_threads != 1) def get_empty_bits(self): return self.l[0] def get_indices(self): @@ -401,7 +411,8 @@ class RefRAM(object): return tree_reduce(operator.mul, list(self.get_empty_bits())) def reveal(self): Program.prog.curr_tape.start_new_basicblock() - res = RAM(self.size, [t.clear_type for t in self.entry_type], self.index) + res = RAM(self.size, [t.clear_type for t in self.entry_type], \ + lambda *args: Array(*args), self.index) for i,a in enumerate(self.l): for j,x in enumerate(a): res.l[i][j] = x.reveal() @@ -422,33 +433,40 @@ class RefRAM(object): class RAM(RefRAM): """ List of entries in memory. """ - def __init__(self, size, entry_type, index=0): + def __init__(self, size, entry_type, get_array, index=0): #print_reg(cint(0), 'r in') self.size = size self.entry_type = entry_type - self.l = [t.dynamic_array(self.size, t) for t in entry_type] + self.l = [get_array(self.size, t) for t in entry_type] self.index = index class AbstractORAM(object): """ Implements reading and writing using read_and_remove and add. """ + @staticmethod + def get_array(size, t, *args, **kwargs): + return t.dynamic_array(size, t, *args, **kwargs) def read(self, index): return self._read(self.value_type.hard_conv(index)) def write(self, index, value): - new_value = [self.value_type.hard_conv(v) \ - for v in (value if isinstance(value, (tuple, list)) \ + new_value = [self.value_type.get_type(length).hard_conv(v) \ + for length,v in zip(self.entry_size, value \ + if isinstance(value, (tuple, list)) \ else (value,))] - return self._write(self.value_type.hard_conv(index), *new_value) + return self._write(self.index_type.hard_conv(index), *new_value) def access(self, index, new_value, write, new_empty=False): - return self._access(self.value_type.hard_conv(index), - self.value_type.hard_conv(write), - self.value_type.hard_conv(new_empty), - *[self.value_type.hard_conv(v) for v in tuplify(new_value)]) + return self._access(self.index_type.hard_conv(index), + self.value_type.bit_type.hard_conv(write), + self.value_type.bit_type.hard_conv(new_empty), + *[self.value_type.get_type(length).hard_conv(v) \ + for length,v in zip(self.entry_size, \ + tuplify(new_value))]) def read_and_maybe_remove(self, index): - return self.read_and_remove(self.value_type.hard_conv(index)), \ + return self.read_and_remove(self.index_type.hard_conv(index)), \ self.state.read() @method_block def _read(self, index): - return self.access(index, (self.value_type(0),) * self.value_length, \ + return self.access(index, tuple(self.value_type.get_type(l)(0) \ + for l in self.entry_size), \ False) @method_block def _write(self, index, *value): @@ -457,7 +475,7 @@ class AbstractORAM(object): def _access(self, index, write, new_empty, *new_value): Program.prog.curr_tape.\ start_new_basicblock(name='abstract-access-remove-%d' % self.size) - index = MemValue(self.value_type.hard_conv(index)) + index = MemValue(self.index_type.hard_conv(index)) read_value, read_empty = self.read_and_remove(index) if len(read_value) != self.value_length: raise Exception('read_and_remove() of %s returns wrong length of ' \ @@ -472,9 +490,10 @@ class AbstractORAM(object): if len(new_value) != self.value_length: raise Exception('wrong length of new value') value = tuple(MemValue(i) for i in if_else(write, new_value, read_value)) - empty = self.value_type.hard_conv(new_empty) + empty = self.value_type.bit_type.hard_conv(new_empty) self.add(Entry(index, value, if_else(write, empty, read_empty), \ - value_type=self.value_type)) + value_type=self.value_type), evict=False) + self.recursive_evict() return read_value, read_empty @method_block def delete(self, index, for_real=True): @@ -490,19 +509,25 @@ class AbstractORAM(object): class EmptyException(Exception): pass -class RefTrivialORAM(object): +class EndRecursiveEviction(object): + recursive_evict = lambda self: None + recursive_evict_rounds = lambda self: itertools.repeat([None]) + +class RefTrivialORAM(EndRecursiveEviction): """ Trivial ORAM reference. """ contiguous = False def empty_entry(self, apply_type=True): - return Entry.get_empty(self.value_type, self.value_length, apply_type) + return Entry.get_empty(self.value_type, self.entry_size, \ + apply_type, self.index_size) def __init__(self, index, oram): self.ram = RefRAM(index, oram) self.index_size = oram.index_size self.value_type, self.value_length = oram.internal_value_type() + self.value_type, self.entry_size = oram.internal_entry_size() self.size = oram.bucket_size def init_mem(self): print 'init trivial oram' - self.ram.init_mem(self.empty_entry()) + self.ram.init_mem(self.empty_entry(apply_type=False)) def search(self, read_index): if use_binary_search and self.value_type == sgf2n: return self.binary_search(read_index) @@ -695,7 +720,7 @@ class RefTrivialORAM(object): Program.prog.security) return [prefix_empty[i+1] - prefix_empty[i] \ for i in range(len(self.ram))] - def add(self, new_entry, state=None): + def add(self, new_entry, state=None, evict=None): # if self.last_index != new_entry.v: # raise Exception('index mismatch: %s / %s' % # (str(self.last_index), str(new_entry.v))) @@ -761,14 +786,17 @@ class TrivialORAM(RefTrivialORAM, AbstractORAM): entry_size=None, contiguous=True, init_rounds=-1): self.index_size = index_size or log2(size) self.value_type = value_type + self.index_type = value_type.get_type(self.index_size) if entry_size is None: self.value_length = value_length + self.entry_size = [None] * value_length else: self.value_length = len(tuplify(entry_size)) + self.entry_size = tuplify(entry_size) self.contiguous = contiguous entry_type = self.empty_entry().types() self.size = size - self.ram = RAM(size, entry_type) + self.ram = RAM(size, entry_type, self.get_array) if init_rounds != -1: # put memory initialization in different timer stop_timer() @@ -789,9 +817,16 @@ def get_n_threads(n_loops): class LinearORAM(TrivialORAM): """ Contiguous ORAM that stores entries in order. """ + @staticmethod + def get_array(size, t, *args, **kwargs): + return Array(size, t, *args, **kwargs) + def __init__(self, *args, **kwargs): + TrivialORAM.__init__(self, *args, **kwargs) + self.index_vector = self.get_array(2 ** self.index_size, \ + self.index_type.bit_type) def read_and_maybe_remove(self, index): return self.read(index), 0 - def add(self, entry, state=None): + def add(self, entry, state=None, evict=None): if entry.created_non_empty is True: self.write(entry.v, entry.x) else: @@ -802,14 +837,14 @@ class LinearORAM(TrivialORAM): def _read(self, index): maybe_start_timer(6) empty_entry = self.empty_entry(False) - index_vector = \ - demux_array(bit_decompose(index, self.index_size)) + demux_array(bit_decompose(index, self.index_size), \ + self.index_vector) @map_sum(get_n_threads(self.size), n_parallel, self.size, \ - self.value_length + 1, [self.value_type] + \ - [self.value_type] * self.value_length) + self.value_length + 1, [self.value_type.bit_type] + \ + [self.value_type.get_type(l) for l in self.entry_size]) def f(i): entry = self.ram[i] - access_here = index_vector[i] + access_here = self.index_vector[i] return access_here * ValueTuple((entry.empty(),) + entry.x) not_found = f()[0] read_value = ValueTuple(f()[1:]) + not_found * empty_entry.x @@ -819,13 +854,13 @@ class LinearORAM(TrivialORAM): def _write(self, index, *new_value): maybe_start_timer(7) empty_entry = self.empty_entry(False) - index_vector = \ - demux_array(bit_decompose(index, self.index_size)) + demux_array(bit_decompose(index, self.index_size), \ + self.index_vector) new_value = make_array(new_value) @for_range_multithread(get_n_threads(self.size), n_parallel, self.size) def f(i): entry = self.ram[i] - access_here = index_vector[i] + access_here = self.index_vector[i] nv = ValueTuple(new_value) delta_entry = \ Entry(0, access_here * (nv - entry.x), \ @@ -841,7 +876,7 @@ class LinearORAM(TrivialORAM): new_empty = MemValue(new_empty) write = MemValue(write) @map_sum(get_n_threads(self.size), n_parallel, self.size, \ - self.value_length + 1, [self.value_type] + \ + self.value_length + 1, [self.value_type.bit_type] + \ [self.value_type] * self.value_length) def f(i): entry = self.ram[i] @@ -892,16 +927,24 @@ class RefBucket(object): child.output() def random_block(length, value_type): - return sum(value_type.get_random_bit() << i for i in range(length)) + return sum(value_type.bit_type.get_random_bit() << i for i in range(length)) -class List(object): +class List(EndRecursiveEviction): """ Debugging only. List which accepts secret values as indices and *reveals* them. """ - def __init__(self, size, value_type, value_length=1, init_rounds=None): + def __init__(self, size, value_type, value_length=1, \ + init_rounds=None, entry_size=None): self.value_type = value_type + self.index_type = value_type.get_type(log2(size)) self.value_length = value_length - self.l = [value_type.dynamic_array(size, value_type) \ + if entry_size is None: + self.l = [value_type.dynamic_array(size, value_type) \ for i in range(value_length)] + else: + self.l = [value_type.dynamic_array(size, \ + value_type.get_type(length)) \ + for length in entry_size] + self.value_length = len(entry_size) for l in self.l: l.assign_all(0) __getitem__ = lambda self,index: [self.l[i][regint(reveal(index))] \ @@ -916,8 +959,9 @@ class List(object): read_and_remove = lambda self,i: (self[i], None) def read_and_maybe_remove(self, *args, **kwargs): return self.read_and_remove(*args, **kwargs), 0 - add = lambda self,entry: self.__setitem__(entry.v.read(), \ - [v.read() for v in entry.x]) + add = lambda self,entry,**kwargs: self.__setitem__(entry.v.read(), \ + [v.read() for v in entry.x]) + recursive_evict = lambda *args,**kwargs: None def batch_init(self, values): for i,value in enumerate(values): index = self.value_type.hard_conv(i) @@ -939,7 +983,7 @@ class LocalIndexStructure(List): def f(i): self.l[0][i] = random_block(entry_size, value_type) print 'index size:', size - def update(self, index, value): + def update(self, index, value, evict=None): read_value = self[index] #print 'read', index, read_value #print self.l @@ -977,13 +1021,18 @@ class TreeORAM(AbstractORAM): self.value_type = value_type if entry_size is not None: self.value_length = len(tuplify(entry_size)) + self.entry_size = tuplify(entry_size) else: self.value_length = value_length + self.entry_size = [None] * value_length self.index_size = log2(size) + self.index_type = value_type.get_type(self.index_size) self.size = size - empty_entry = Entry.get_empty(*self.internal_value_type()) + empty_entry = Entry.get_empty(*self.internal_entry_size(), \ + index_size=self.D) self.entry_type = empty_entry.types() - self.ram = RAM(self.n_buckets() * self.bucket_size, self.entry_type) + self.ram = RAM(self.n_buckets() * self.bucket_size, self.entry_type, \ + self.get_array) if init_rounds != -1: # put memory initialization in different timer stop_timer() @@ -996,7 +1045,7 @@ class TreeORAM(AbstractORAM): self.index = self.index_structure(size, self.D, value_type, init_rounds, True) self.read_value = Array(self.value_length, value_type) - self.read_non_empty = MemValue(self.value_type(0)) + self.read_non_empty = MemValue(self.value_type.bit_type(0)) self.state = MemValue(self.value_type(0)) @method_block def add_to_root(self, state, is_empty, v, *x): @@ -1011,7 +1060,7 @@ class TreeORAM(AbstractORAM): entry = bucket.bucket.pop() #print 'evict', entry #print 'from', bucket - b = if_else(entry.empty(), self.value_type.get_random_bit(), \ + b = if_else(entry.empty(), self.value_type.bit_type.get_random_bit(), \ get_bit(entry.x[0], self.D - 1 - d, self.D)) block = cond_swap(b, entry, self.root.bucket.empty_entry()) #print 'empty', entry.empty() @@ -1042,7 +1091,7 @@ class TreeORAM(AbstractORAM): new_path = regint.get_random(self.D) l_star = self.value_type(new_path) self.state.write(l_star) - return self.index.update(u, l_star).reveal() + return self.index.update(u, l_star, evict=False).reveal() @method_block def read_and_remove_levels(self, u, read_path): u = MemValue(u) @@ -1050,7 +1099,7 @@ class TreeORAM(AbstractORAM): levels = self.D + 1 parallel = get_parallel(self.index_size, *self.internal_value_type()) @map_sum(get_n_threads_for_tree(self.size), parallel, levels, \ - self.value_length + 1, [self.value_type] + \ + self.value_length + 1, [self.value_type.bit_type] + \ [self.value_type] * self.value_length) def process(level): b_index = regint(cint(2**(self.D) + read_path) >> cint(self.D - level)) @@ -1074,6 +1123,8 @@ class TreeORAM(AbstractORAM): crash() def internal_value_type(self): return self.value_type, self.value_length + 1 + def internal_entry_size(self): + return self.value_type, [self.D] + list(self.entry_size) def n_buckets(self): return 2**(self.D+1) @method_block @@ -1097,7 +1148,7 @@ class TreeORAM(AbstractORAM): Program.prog.curr_tape.\ start_new_basicblock(name='read_and_remove-%d-end' % self.size) return [MemValue(v) for v in read_value], MemValue(read_empty) - def add(self, entry, state=None): + def add(self, entry, state=None, evict=None): if state is None: state = self.state.read() #print_reg(cint(0), 'add') @@ -1141,6 +1192,9 @@ class TreeORAM(AbstractORAM): #print 'd, 2^d', d, 1 << d self.evict2(s1 + (1 << d), s2 + (1 << d), d) self.check() + def recursive_evict(self): + self.evict() + self.index.recursive_evict() def batch_init(self, values): """ Batch initalization. Obliviously shuffles and adds N entries to @@ -1349,11 +1403,11 @@ class PackedIndexStructure(object): self.entry_size = tuplify(entry_size) self.value_type = value_type for demux_bits in range(max_demux_bits + 1): - self.log_entries_per_element = min(size, \ + self.log_entries_per_element = min(log2(size), \ int(math.floor(math.log(float(get_value_size(value_type)) / \ sum(self.entry_size), 2)))) self.log_elements_per_block = \ - max(0, min(demux_bits, log2(size * sum(self.entry_size)) - \ + max(0, min(demux_bits, log2(size) - \ self.log_entries_per_element)) if self.log_entries_per_element < 0: self.entries_per_block = 1 @@ -1388,14 +1442,17 @@ class PackedIndexStructure(object): print 'log(elements per block):', self.log_elements_per_block print 'elements per block:', self.elements_per_block print 'used bits:', self.used_bits + entry_size = [self.used_bits] * self.elements_per_block if real_size > 1: # no need to init underlying ORAM, will be initialized implicitely - self.l = self.storage(real_size, value_type, self.elements_per_block, \ - init_rounds=0) + self.l = self.storage(real_size, value_type, \ + entry_size=entry_size, init_rounds=0) self.small = False else: - self.l = List(1, value_type, self.elements_per_block) + self.l = List(1, value_type, self.elements_per_block, \ + entry_size=entry_size) self.small = True + self.index_type = self.l.index_type if init_rounds: if init_rounds > 0: real_init_rounds = init_rounds * real_size / size @@ -1484,20 +1541,20 @@ class PackedIndexStructure(object): return self.MultiSlicer(self, index) else: return self.Slicer(self, index) - def update(self, index, value): + def update(self, index, value, evict=True): """ Updating index return current value. Has to be done in one step to avoid exponential blow-up in ORAM recursion. """ - return self.access(index, value, True) - def access(self, index, value, write): + return self.access(index, value, True, evict=evict) + def access(self, index, value, write, evict=True): slicer = self.get_slicer(index) block = self.l.read_and_maybe_remove(slicer.a)[0][0] read_value = slicer.read(block) value = if_else(write, ValueTuple(tuplify(value)), \ ValueTuple(read_value)) - self.l.add(Entry(MemValue(self.value_type(slicer.a)), \ + self.l.add(Entry(MemValue(self.l.index_type(slicer.a)), \ ValueTuple(MemValue(v) \ for v in slicer.write(value)), \ - value_type=self.value_type)) + value_type=self.value_type), evict=evict) return untuplify(read_value) def __getitem__(self, index): slicer = self.get_slicer(index) @@ -1507,7 +1564,9 @@ class PackedIndexStructure(object): # no need for reading first self.l[index] = self.get_slicer(index).write(value) else: - self.access(index, value, True) + self.access(index, value, True, False) + self.l.recursive_evict() + recursive_evict = lambda self: self.l.recursive_evict() def batch_init(self, values): """ Initialize m values with indices 0, ..., m-1 """ @@ -1551,8 +1610,8 @@ class PackedORAMWithEmpty(AbstractORAM, PackedIndexStructure): return res[1:], 1 - res[0] def read_and_maybe_remove(self, index): return self.read(index), 0 - def add(self, entry, state=None): - self.access(entry.v, entry.x, True, entry.empty()) + def add(self, entry, state=None, evict=True): + self.access(entry.v, entry.x, True, entry.empty(), evict=evict) class LocalPackedIndexStructure(PackedIndexStructure): """ Debugging only. Packed tree ORAM index revealing the access @@ -1621,30 +1680,39 @@ class OptimalPackedORAMWithEmpty(PackedORAMWithEmpty): storage = OptimalORAM def test_oram(oram_type, N, value_type=sint, iterations=100): + stop_grind() oram = oram_type(N, value_type=value_type, entry_size=32, init_rounds=0) + value_type = value_type.get_type(32) + index_type = value_type.get_type(log2(N)) + start_grind() print 'initialized' print_ln('initialized') stop_timer() # synchronize + start_timer(2) Program.prog.curr_tape.start_new_basicblock(name='sync') value_type(0).reveal() Program.prog.curr_tape.start_new_basicblock(name='sync') + stop_timer(2) start_timer() #oram[value_type(0)] = -1 #iterations = N @for_range(iterations) def f(i): - oram[value_type(i % N)] = value_type(i % N) + time() + oram[index_type(i % N)] = value_type(i % N) #value, empty = oram.read_and_remove(value_type(i)) #print 'first write' time() - oram[value_type(i % N)].reveal().print_reg('writ') + oram[index_type(i % N)].reveal().print_reg('writ') #print 'first read' @for_range(iterations) def f(i): - x = oram[value_type(i % N)] + time() + x = oram[index_type(i % N)] x.reveal().print_reg('read') # print 'second read' + print_ln('%s accesses', 3 * iterations) return oram def test_oram_access(oram_type, N, value_type=sint, index_size=None, iterations=100): diff --git a/Compiler/path_oram.py b/Compiler/path_oram.py index 80a93f45..f092a536 100644 --- a/Compiler/path_oram.py +++ b/Compiler/path_oram.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt if '_Array' not in dir(): from oram import * @@ -147,13 +147,17 @@ class PathORAM(TreeORAM): self.value_type = value_type if entry_size is not None: self.value_length = len(tuplify(entry_size)) + self.entry_size = tuplify(entry_size) else: self.value_length = value_length + self.entry_size = [None] * value_length self.index_size = log2(size) + self.index_type = value_type.get_type(self.index_size) self.size = size - self.entry_type = Entry.get_empty(*self.internal_value_type()).types() + self.entry_type = Entry.get_empty(*self.internal_entry_size()).types() - self.buckets = RAM(self.bucket_size * 2**(self.D+1), self.entry_type) + self.buckets = RAM(self.bucket_size * 2**(self.D+1), self.entry_type, + self.get_array) if init_rounds != -1: # put memory initialization in different timer stop_timer() @@ -197,15 +201,15 @@ class PathORAM(TreeORAM): # temp storage for the path + stash in eviction self.temp_size = stash_size + self.bucket_size*(self.D+1) - self.temp_storage = RAM(self.temp_size, self.entry_type) + self.temp_storage = RAM(self.temp_size, self.entry_type, self.get_array) self.temp_levels = [0] * self.temp_size # Array(self.temp_size, 'c') for i in range(self.temp_size): self.temp_levels[i] = 0 # these include a read value from the stash - self.read_value = [Array(self.D + 2, self.value_type) - for i in range(self.value_length)] - self.read_empty = Array(self.D + 2, self.value_type) + self.read_value = [Array(self.D + 2, self.value_type.get_type(l)) + for l in self.entry_size] + self.read_empty = Array(self.D + 2, self.value_type.bit_type) self.state = MemValue(self.value_type(0)) self.eviction_count = MemValue(cint(0)) @@ -242,7 +246,8 @@ class PathORAM(TreeORAM): for j, ram_index in enumerate(ram_indices): self.temp_storage[i*self.bucket_size + j] = self.buckets[ram_index] self.temp_levels[i*self.bucket_size + j] = i - self.buckets[ram_index] = Entry.get_empty(self.value_type, 1) + ies = self.internal_entry_size() + self.buckets[ram_index] = Entry.get_empty(*ies) # load the stash for i in range(len(self.stash.ram)): @@ -253,7 +258,7 @@ class PathORAM(TreeORAM): entry = self.stash.ram[i] self.temp_storage[i + self.bucket_size*(self.D+1)] = entry - te = Entry.get_empty(self.value_type, 1) + te = Entry.get_empty(*self.internal_entry_size()) self.stash.ram[i] = te self.path_regs = [None] * self.bucket_size*(self.D+1) @@ -268,11 +273,11 @@ class PathORAM(TreeORAM): #self.sizes = [Counter(0, max_val=4) for i in range(self.D + 1)] if self.use_shuffle_evict: if self.bucket_size == 4: - self.size_bits = [[self.value_type(i) for i in (0, 0, 0, 1)] for j in range(self.D+1)] + self.size_bits = [[self.value_type.bit_type(i) for i in (0, 0, 0, 1)] for j in range(self.D+1)] elif self.bucket_size == 2 or self.bucket_size == 3: - self.size_bits = [[self.value_type(i) for i in (0, 0)] for j in range(self.D+1)] + self.size_bits = [[self.value_type.bit_type(i) for i in (0, 0)] for j in range(self.D+1)] else: - self.size_bits = [[self.value_type(0) for i in range(self.bucket_size)] for j in range(self.D+1)] + self.size_bits = [[self.value_type.bit_type(0) for i in range(self.bucket_size)] for j in range(self.D+1)] self.stash_size = Counter(0, max_val=len(self.stash.ram)) leaf = self.state.read().reveal() @@ -308,7 +313,7 @@ class PathORAM(TreeORAM): empty_entry = self.empty_entry(False) skip = 1 - found = Array(self.bucket_size, self.value_type) + found = Array(self.bucket_size, self.value_type.bit_type) entries = [self.buckets[j] for j in ram_indices] indices = [e.v for e in entries] empty_bits = [e.empty() for e in entries] @@ -341,8 +346,8 @@ class PathORAM(TreeORAM): self.read_empty[self.D+1] = empty def empty_entry(self, apply_type=True): - vtype, vlength = self.internal_value_type() - return Entry.get_empty(vtype, vlength, apply_type) + vtype, entry_size = self.internal_entry_size() + return Entry.get_empty(vtype, entry_size, apply_type, self.index_size) def shuffle_evict(self, leaf): """ Evict using oblivious shuffling etc """ @@ -409,25 +414,25 @@ class PathORAM(TreeORAM): if self.bucket_size == 4: c = s[0]*s[1] if self.value_type == sgf2n: - empty_bits_and_levels[j][0] = [1 - self.value_type(s[0] + s[1] + s[2] + c), self.value_type.clear_type(j)] - empty_bits_and_levels[j][1] = [1 - self.value_type(s[1] + s[2]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][2] = [1 - self.value_type(c + s[2]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][3] = [1 - self.value_type(s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] + s[2] + c), self.value_type.clear_type(j)] + empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][3] = [1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j)] else: - empty_bits_and_levels[j][0] = [1 - self.value_type(s[0] + s[1] - c + s[2]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][1] = [1 - self.value_type(s[1] + s[2]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][2] = [1 - self.value_type(c + s[2]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][3] = [1 - self.value_type(s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] - c + s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1] + s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c + s[2]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][3] = [1 - self.value_type.bit_type(s[2]), self.value_type.clear_type(j)] elif self.bucket_size == 2: if evict_debug: print_str('%s,%s,', s[0].reveal(), s[1].reveal()) - empty_bits_and_levels[j][0] = [1 - self.value_type(s[0] + s[1]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][1] = [1 - self.value_type(s[1]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j)] elif self.bucket_size == 3: c = s[0]*s[1] - empty_bits_and_levels[j][0] = [1 - self.value_type(s[0] + s[1] - c), self.value_type.clear_type(j)] - empty_bits_and_levels[j][1] = [1 - self.value_type(s[1]), self.value_type.clear_type(j)] - empty_bits_and_levels[j][2] = [1 - self.value_type(c), self.value_type.clear_type(j)] + empty_bits_and_levels[j][0] = [1 - self.value_type.bit_type(s[0] + s[1] - c), self.value_type.clear_type(j)] + empty_bits_and_levels[j][1] = [1 - self.value_type.bit_type(s[1]), self.value_type.clear_type(j)] + empty_bits_and_levels[j][2] = [1 - self.value_type.bit_type(c), self.value_type.clear_type(j)] if evict_debug: print_ln() @@ -471,7 +476,7 @@ class PathORAM(TreeORAM): merged_entries = [e for e in merged_entries if e is not None] # need to copy entries/levels to memory for re-positioning - entries_ram = RAM(self.temp_size, self.entry_type) + entries_ram = RAM(self.temp_size, self.entry_type, self.get_array) levels_array = Array(self.temp_size, cint) for i,entrylev in enumerate(merged_entries): @@ -570,10 +575,10 @@ class PathORAM(TreeORAM): def adjust_lca(self, lca_bits, lev, not_empty, prnt=False): """ Adjust LCA based on bucket capacities (and original clear level, lev) """ - found = self.value_type(0) - assigned = self.value_type(0) - try_add_here = self.value_type(0) - new_lca = [self.value_type(0)] * (self.D + 1) + found = self.value_type.bit_type(0) + assigned = self.value_type.bit_type(0) + try_add_here = self.value_type.bit_type(0) + new_lca = [self.value_type.bit_type(0)] * (self.D + 1) upper = min(lev + self.sigma, self.D) lower = max(lev - self.tau, 0) @@ -639,7 +644,7 @@ class PathORAM(TreeORAM): a_bits = bit_decompose(a, self.D) b_bits = bit_decompose(b, self.D) found = [None] * self.D - not_found = self.value_type(not_empty) #1 + not_found = self.value_type.bit_type(not_empty) #1 if limit is None: limit = self.D @@ -722,13 +727,13 @@ class PathORAM(TreeORAM): return levstar, a - def add(self, entry, state=None): + def add(self, entry, state=None, evict=True): if state is None: state = self.state.read() l = state - x = tuple((self.value_type(i.read())) for i in entry.x) + x = tuple(i.read() for i in entry.x) - e = Entry(self.value_type(entry.v.read()), (l,) + x, entry.empty()) + e = Entry(entry.v.read(), (l,) + x, entry.empty()) #self.temp_storage[self.temp_size-1] = e * 1 #self.temp_levels[self.temp_size-1] = 0 @@ -738,7 +743,8 @@ class PathORAM(TreeORAM): except Exception: print self raise - self.evict() + if evict: + self.evict() class LocalPathORAM(PathORAM): """ Debugging only. Path ORAM using index revealing the access diff --git a/Compiler/permutation.py b/Compiler/permutation.py index 9284bff4..8d7cfe71 100644 --- a/Compiler/permutation.py +++ b/Compiler/permutation.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from random import randint import math @@ -361,7 +361,7 @@ def rec_shuffle(x, config=None, value_type=sgf2n, reverse=False): if config is None: config = configure_waksman(random_perm(n)) for i,c in enumerate(config): - config[i] = [value_type(b) for b in c] + config[i] = [value_type.bit_type(b) for b in c] waksman(x, config, reverse=reverse) waksman(x, config, reverse=reverse) diff --git a/Compiler/program.py b/Compiler/program.py index c65d5f39..74cc4627 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler.config import * from Compiler.exceptions import * @@ -66,6 +66,8 @@ class Program(object): self.free_threads = set() self.public_input_file = open(self.programs_dir + '/Public-Input/%s' % self.name, 'w') self.types = {} + self.to_merge = [Compiler.instructions.startopen_class] + self.stop_class = Compiler.instructions.stopopen_class Program.prog = self self.reset_values() @@ -125,6 +127,7 @@ class Program(object): self.name = progname if len(args) > 1: self.name += '-' + '-'.join(args[1:]) + self.progname = progname def new_tape(self, function, args=[], name=None): if name is None: @@ -534,7 +537,9 @@ class Tape: (block.name, i, len(self.basicblocks), \ len(block.instructions)) # the next call is necessary for allocation later even without merging - merger = al.Merger(block, options) + merger = al.Merger(block, options, \ + tuple(self.program.to_merge), \ + self.program.stop_class) if options.dead_code_elimination: if len(block.instructions) > 10000: print 'Eliminate dead code...' @@ -545,8 +550,8 @@ class Tape: block.defined_registers = set() continue if len(block.instructions) > 10000: - print 'Merging open instructions...' - numrounds = merger.longest_paths_merge() + print 'Merging instructions...' + numrounds = merger.longest_paths_merge(self.program.stop_class != type(None)) if numrounds > 0: print 'Program requires %d rounds of communication' % numrounds numinv = sum(len(i.args) for i in block.instructions if isinstance(i, Compiler.instructions.startopen_class)) @@ -555,7 +560,9 @@ class Tape: if options.dead_code_elimination: block.instructions = filter(lambda x: x is not None, block.instructions) if not (options.merge_opens and self.merge_opens): - print 'Not merging open instructions in tape %s' % self.name + print 'Not merging instructions in tape %s' % self.name + else: + print 'Rounds determined by', self.program.to_merge # add jumps offset = 0 diff --git a/Compiler/tools.py b/Compiler/tools.py index ac3c0abf..cf350624 100644 --- a/Compiler/tools.py +++ b/Compiler/tools.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import itertools @@ -7,3 +7,9 @@ class chain(object): self.args = args def __iter__(self): return itertools.chain(*self.args) + +class cycle(object): + def __init__(self, *args): + self.args = args + def __iter__(self): + return itertools.cycle(*self.args) diff --git a/Compiler/types.py b/Compiler/types.py index 19965ece..1e61d6a5 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler.program import Tape from Compiler.exceptions import * @@ -791,13 +791,8 @@ class regint(_register, _int): return cint(self).mod2m(*args, **kwargs) def bit_decompose(self, bit_length=None): - res = [] - x = self - two = regint(2) - for i in range(bit_length or program.bit_length): - y = x / two - res.append(x - two * y) - x = y + res = [regint() for i in range(bit_length or program.bit_length)] + bitdecint(self, *res) return res @staticmethod @@ -819,6 +814,9 @@ class regint(_register, _int): class _secret(_register): __slots__ = [] + PreOR = staticmethod(lambda l: floatingpoint.PreORC(l)) + PreOp = staticmethod(lambda op, l: floatingpoint.PreOpL(op, l)) + @vectorized_classmethod @set_instruction_type def protect_memory(cls, start, end): @@ -971,6 +969,9 @@ class sint(_secret, _int): clear_type = cint reg_type = 's' + PreOp = staticmethod(floatingpoint.PreOpL) + PreOR = staticmethod(floatingpoint.PreOR) + @vectorized_classmethod def get_random_int(cls, bits): res = sint() @@ -1164,6 +1165,10 @@ class sgf2n(_secret, _gf2n): clear_type = cgf2n reg_type = 'sg' + @classmethod + def get_type(cls, length): + return cls + @classmethod def get_raw_input_from(cls, player): res = cls() @@ -1265,8 +1270,10 @@ class sgf2n(_secret, _gf2n): masked = sum([b * (one << wanted_positions[i]) for i,b in enumerate(random_bits)], self).reveal() return [self.clear_type((masked >> wanted_positions[i]) & one) + r for i,r in enumerate(random_bits)] -sint.basic_type = sint -sgf2n.basic_type = sgf2n +for t in (sint, sgf2n): + t.bit_type = t + t.basic_type = t + t.default_type = t class sgf2nint(sgf2n): @@ -2305,13 +2312,13 @@ class Array(object): self[i] = value[source_index] source_index.iadd(1) return - self._store(self.value_type.conv(value), self.get_address(index)) + self._store(value, self.get_address(index)) def _load(self, address): return self.value_type.load_mem(address) def _store(self, value, address): - value.store_in_mem(address) + self.value_type.conv(value).store_in_mem(address) def __len__(self): return self.length @@ -2335,10 +2342,10 @@ class Array(object): self[i] = j return self - def assign_all(self, value): - mem_value = self.value_type.MemValue(value) - n_loops = 8 if len(self) > 2**20 else 1 - @library.for_range_multithread(n_loops, 1024, len(self)) + def assign_all(self, value, use_threads=True): + mem_value = MemValue(value) + n_threads = 8 if use_threads and len(self) > 2**20 else 1 + @library.for_range_multithread(n_threads, 1024, len(self)) def f(i): self[i] = mem_value return self diff --git a/Compiler/util.py b/Compiler/util.py index 25bfb0b1..895bbaf3 100644 --- a/Compiler/util.py +++ b/Compiler/util.py @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import math import operator diff --git a/Exceptions/Exceptions.h b/Exceptions/Exceptions.h index 7f4c9777..2b54b8a0 100644 --- a/Exceptions/Exceptions.h +++ b/Exceptions/Exceptions.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Exceptions #define _Exceptions diff --git a/ExternalIO/README.md b/ExternalIO/README.md index 93ff4b43..cb418b2d 100644 --- a/ExternalIO/README.md +++ b/ExternalIO/README.md @@ -1,4 +1,4 @@ -(C) 2018 University of Bristol. See License.txt. +(C) 2018 University of Bristol, Bar-Ilan University. See License.txt. The ExternalIO directory contains examples of managing I/O between external client processes and SPDZ parties running SPDZ engines. These instructions assume that SPDZ has been built as per the [project readme](../README.md). diff --git a/ExternalIO/bankers-bonus-client.cpp b/ExternalIO/bankers-bonus-client.cpp index 7740c7f1..0ca636fa 100644 --- a/ExternalIO/bankers-bonus-client.cpp +++ b/ExternalIO/bankers-bonus-client.cpp @@ -1,5 +1,5 @@ /* - * (C) 2018 University of Bristol. See License.txt + * (C) 2018 University of Bristol, Bar-Ilan University. See License.txt * * Demonstrate external client inputing and receiving outputs from a SPDZ process, * following the protocol described in https://eprint.iacr.org/2015/1006.pdf. diff --git a/ExternalIO/bankers-bonus-commsec-client.cpp b/ExternalIO/bankers-bonus-commsec-client.cpp index 9ea927d8..3094d4f0 100644 --- a/ExternalIO/bankers-bonus-commsec-client.cpp +++ b/ExternalIO/bankers-bonus-commsec-client.cpp @@ -1,5 +1,5 @@ /* - * (C) 2018 University of Bristol. See License.txt + * (C) 2018 University of Bristol, Bar-Ilan University. See License.txt * * Demonstrate external client inputing and receiving outputs from a SPDZ process, * following the protocol described in https://eprint.iacr.org/2015/1006.pdf. diff --git a/FHE/AddableVector.h b/FHE/AddableVector.h index 3d973ff0..5e2034fb 100644 --- a/FHE/AddableVector.h +++ b/FHE/AddableVector.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * AddableVector.h diff --git a/FHE/Ciphertext.cpp b/FHE/Ciphertext.cpp index c844709b..6c611739 100644 --- a/FHE/Ciphertext.cpp +++ b/FHE/Ciphertext.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Ciphertext.h" #include "Exceptions/Exceptions.h" diff --git a/FHE/Ciphertext.h b/FHE/Ciphertext.h index 9a5275c2..b5cbf6ef 100644 --- a/FHE/Ciphertext.h +++ b/FHE/Ciphertext.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Ciphertext #define _Ciphertext diff --git a/FHE/DiscreteGauss.cpp b/FHE/DiscreteGauss.cpp index 1b91843e..d2e49445 100644 --- a/FHE/DiscreteGauss.cpp +++ b/FHE/DiscreteGauss.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "DiscreteGauss.h" diff --git a/FHE/DiscreteGauss.h b/FHE/DiscreteGauss.h index 1c11c707..3b9df89a 100644 --- a/FHE/DiscreteGauss.h +++ b/FHE/DiscreteGauss.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _DiscreteGauss #define _DiscreteGauss diff --git a/FHE/FFT.cpp b/FHE/FFT.cpp index ff7421de..2ffd30c2 100644 --- a/FHE/FFT.cpp +++ b/FHE/FFT.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/FFT.h" diff --git a/FHE/FFT.h b/FHE/FFT.h index e9467180..84b69fe4 100644 --- a/FHE/FFT.h +++ b/FHE/FFT.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FFT #define _FFT diff --git a/FHE/FFT_Data.cpp b/FHE/FFT_Data.cpp index 46c43469..53b8ff9d 100644 --- a/FHE/FFT_Data.cpp +++ b/FHE/FFT_Data.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/FFT_Data.h" #include "FHE/FFT.h" diff --git a/FHE/FFT_Data.h b/FHE/FFT_Data.h index 1bc8ae7a..ae4f1626 100644 --- a/FHE/FFT_Data.h +++ b/FHE/FFT_Data.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FFT_Data #define _FFT_Data diff --git a/FHE/FHE_Keys.cpp b/FHE/FHE_Keys.cpp index 928b582c..2a0bbc36 100644 --- a/FHE/FHE_Keys.cpp +++ b/FHE/FHE_Keys.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE_Keys.h" diff --git a/FHE/FHE_Keys.h b/FHE/FHE_Keys.h index 7983a1c3..87ebce0d 100644 --- a/FHE/FHE_Keys.h +++ b/FHE/FHE_Keys.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FHE_Keys #define _FHE_Keys diff --git a/FHE/FHE_Params.cpp b/FHE/FHE_Params.cpp index 0b361711..33b10c48 100644 --- a/FHE/FHE_Params.cpp +++ b/FHE/FHE_Params.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE_Params.h" diff --git a/FHE/FHE_Params.h b/FHE/FHE_Params.h index c10a15fe..860de55e 100644 --- a/FHE/FHE_Params.h +++ b/FHE/FHE_Params.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FHE_Params #define _FHE_Params diff --git a/FHE/Generator.h b/FHE/Generator.h index cbd5e16f..913ba11a 100644 --- a/FHE/Generator.h +++ b/FHE/Generator.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Generator.h diff --git a/FHE/Matrix.cpp b/FHE/Matrix.cpp index 608fd38b..d44850c6 100644 --- a/FHE/Matrix.cpp +++ b/FHE/Matrix.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/Matrix.h" diff --git a/FHE/Matrix.h b/FHE/Matrix.h index 97bb4cbb..0080d9a2 100644 --- a/FHE/Matrix.h +++ b/FHE/Matrix.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _myHNF diff --git a/FHE/NTL-Subs.cpp b/FHE/NTL-Subs.cpp index f3e52e74..443dd8e5 100644 --- a/FHE/NTL-Subs.cpp +++ b/FHE/NTL-Subs.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/NTL-Subs.h" diff --git a/FHE/NTL-Subs.h b/FHE/NTL-Subs.h index 5292748e..797347a2 100644 --- a/FHE/NTL-Subs.h +++ b/FHE/NTL-Subs.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _NTL_Subs #define _NTL_Subs diff --git a/FHE/NoiseBounds.cpp b/FHE/NoiseBounds.cpp index 60ac75ba..9a415ab3 100644 --- a/FHE/NoiseBounds.cpp +++ b/FHE/NoiseBounds.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * NoiseBound.cpp diff --git a/FHE/NoiseBounds.h b/FHE/NoiseBounds.h index 98c430e5..772f8dd5 100644 --- a/FHE/NoiseBounds.h +++ b/FHE/NoiseBounds.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * NoiseBound.h diff --git a/FHE/P2Data.cpp b/FHE/P2Data.cpp index ec500d90..04a8bf23 100644 --- a/FHE/P2Data.cpp +++ b/FHE/P2Data.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/P2Data.h" diff --git a/FHE/P2Data.h b/FHE/P2Data.h index 1b2d6d60..49972af2 100644 --- a/FHE/P2Data.h +++ b/FHE/P2Data.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _P2Data #define _P2Data diff --git a/FHE/PPData.cpp b/FHE/PPData.cpp index 2d78eab2..98d57051 100644 --- a/FHE/PPData.cpp +++ b/FHE/PPData.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/Subroutines.h" #include "FHE/PPData.h" diff --git a/FHE/PPData.h b/FHE/PPData.h index 89dc7a67..0ccf5047 100644 --- a/FHE/PPData.h +++ b/FHE/PPData.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _PPData #define _PPData diff --git a/FHE/Plaintext.cpp b/FHE/Plaintext.cpp index c977d3e3..bd4ecfc7 100644 --- a/FHE/Plaintext.cpp +++ b/FHE/Plaintext.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/Plaintext.h" diff --git a/FHE/Plaintext.h b/FHE/Plaintext.h index 9df5d727..5dcbd95f 100644 --- a/FHE/Plaintext.h +++ b/FHE/Plaintext.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Plaintext #define _Plaintext diff --git a/FHE/QGroup.cpp b/FHE/QGroup.cpp index 3ddec931..65008eb9 100644 --- a/FHE/QGroup.cpp +++ b/FHE/QGroup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Matrix.h" diff --git a/FHE/QGroup.h b/FHE/QGroup.h index 862690e6..75b6862a 100644 --- a/FHE/QGroup.h +++ b/FHE/QGroup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _QGroup #define _QGroup diff --git a/FHE/Random_Coins.cpp b/FHE/Random_Coins.cpp index ff47e816..ba782810 100644 --- a/FHE/Random_Coins.cpp +++ b/FHE/Random_Coins.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Random_Coins.h" diff --git a/FHE/Random_Coins.h b/FHE/Random_Coins.h index ff68f9e6..fb334c8a 100644 --- a/FHE/Random_Coins.h +++ b/FHE/Random_Coins.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Random_Coins #define _Random_Coins diff --git a/FHE/Ring.cpp b/FHE/Ring.cpp index f2dc672f..7e54851b 100644 --- a/FHE/Ring.cpp +++ b/FHE/Ring.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Ring.h" diff --git a/FHE/Ring.h b/FHE/Ring.h index d035aaec..b25173d1 100644 --- a/FHE/Ring.h +++ b/FHE/Ring.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Ring #define _Ring diff --git a/FHE/Ring_Element.cpp b/FHE/Ring_Element.cpp index b9ba4997..8ab187f2 100644 --- a/FHE/Ring_Element.cpp +++ b/FHE/Ring_Element.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHE/Ring_Element.h" diff --git a/FHE/Ring_Element.h b/FHE/Ring_Element.h index 4c88d89a..03ad143c 100644 --- a/FHE/Ring_Element.h +++ b/FHE/Ring_Element.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Ring_Element #define _Ring_Element diff --git a/FHE/Rq_Element.cpp b/FHE/Rq_Element.cpp index e2834320..5008db58 100644 --- a/FHE/Rq_Element.cpp +++ b/FHE/Rq_Element.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Rq_Element.h" #include "Exceptions/Exceptions.h" diff --git a/FHE/Rq_Element.h b/FHE/Rq_Element.h index 55fc912b..546ff2b5 100644 --- a/FHE/Rq_Element.h +++ b/FHE/Rq_Element.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Rq_Element #define _Rq_Element diff --git a/FHE/tools.h b/FHE/tools.h index cbbfe81e..4ebabbe4 100644 --- a/FHE/tools.h +++ b/FHE/tools.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * tools.h diff --git a/FHEOffline/CutAndChooseMachine.cpp b/FHEOffline/CutAndChooseMachine.cpp index 03a19d0b..b33ce667 100644 --- a/FHEOffline/CutAndChooseMachine.cpp +++ b/FHEOffline/CutAndChooseMachine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * CutAndChooseMachine.cpp diff --git a/FHEOffline/CutAndChooseMachine.h b/FHEOffline/CutAndChooseMachine.h index a88011f1..8ac6fcdb 100644 --- a/FHEOffline/CutAndChooseMachine.h +++ b/FHEOffline/CutAndChooseMachine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * CutAndChooseMachine.h diff --git a/FHEOffline/DataSetup.cpp b/FHEOffline/DataSetup.cpp index a41c3c96..866640fa 100644 --- a/FHEOffline/DataSetup.cpp +++ b/FHEOffline/DataSetup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * DataSetup.cpp diff --git a/FHEOffline/DataSetup.h b/FHEOffline/DataSetup.h index 1b623454..75779b3d 100644 --- a/FHEOffline/DataSetup.h +++ b/FHEOffline/DataSetup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * DataSetup.h diff --git a/FHEOffline/DistDecrypt.cpp b/FHEOffline/DistDecrypt.cpp index 28453559..2e5a077c 100644 --- a/FHEOffline/DistDecrypt.cpp +++ b/FHEOffline/DistDecrypt.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "DistDecrypt.h" diff --git a/FHEOffline/DistDecrypt.h b/FHEOffline/DistDecrypt.h index d5a18fe0..ea09671c 100644 --- a/FHEOffline/DistDecrypt.h +++ b/FHEOffline/DistDecrypt.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _DistDecrypt #define _DistDecrypt diff --git a/FHEOffline/DistKeyGen.cpp b/FHEOffline/DistKeyGen.cpp index dcd572b6..6fd3be67 100644 --- a/FHEOffline/DistKeyGen.cpp +++ b/FHEOffline/DistKeyGen.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * DistKeyGen.cpp diff --git a/FHEOffline/DistKeyGen.h b/FHEOffline/DistKeyGen.h index 27220d87..6d935b4c 100644 --- a/FHEOffline/DistKeyGen.h +++ b/FHEOffline/DistKeyGen.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * DistKeyGen.h diff --git a/FHEOffline/EncCommit.cpp b/FHEOffline/EncCommit.cpp index 0c987431..759d4ef5 100644 --- a/FHEOffline/EncCommit.cpp +++ b/FHEOffline/EncCommit.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Auth/Subroutines.h" diff --git a/FHEOffline/EncCommit.h b/FHEOffline/EncCommit.h index f11ae464..4ef48aa1 100644 --- a/FHEOffline/EncCommit.h +++ b/FHEOffline/EncCommit.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _EncCommit #define _EncCommit diff --git a/FHEOffline/FHE-Subroutines.cpp b/FHEOffline/FHE-Subroutines.cpp index 96832896..57a54723 100644 --- a/FHEOffline/FHE-Subroutines.cpp +++ b/FHEOffline/FHE-Subroutines.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Auth/Subroutines.h" diff --git a/FHEOffline/FullSetup.cpp b/FHEOffline/FullSetup.cpp index bfcf6250..885d7eb2 100644 --- a/FHEOffline/FullSetup.cpp +++ b/FHEOffline/FullSetup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHEOffline/FullSetup.h" diff --git a/FHEOffline/FullSetup.h b/FHEOffline/FullSetup.h index e741a834..beccb6d2 100644 --- a/FHEOffline/FullSetup.h +++ b/FHEOffline/FullSetup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FullSetup #define _FullSetup diff --git a/FHEOffline/Multiplier.cpp b/FHEOffline/Multiplier.cpp index 5f80fcef..ca35ad11 100644 --- a/FHEOffline/Multiplier.cpp +++ b/FHEOffline/Multiplier.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Multiplier.cpp diff --git a/FHEOffline/Multiplier.h b/FHEOffline/Multiplier.h index f6048cdb..8f037938 100644 --- a/FHEOffline/Multiplier.h +++ b/FHEOffline/Multiplier.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Multiplier.h diff --git a/FHEOffline/PairwiseGenerator.cpp b/FHEOffline/PairwiseGenerator.cpp index 591ab570..d7616c2c 100644 --- a/FHEOffline/PairwiseGenerator.cpp +++ b/FHEOffline/PairwiseGenerator.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseGenerator.cpp diff --git a/FHEOffline/PairwiseGenerator.h b/FHEOffline/PairwiseGenerator.h index f87485b4..85d4162d 100644 --- a/FHEOffline/PairwiseGenerator.h +++ b/FHEOffline/PairwiseGenerator.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseGenerator.h diff --git a/FHEOffline/PairwiseMachine.cpp b/FHEOffline/PairwiseMachine.cpp index 0abb3a71..deed2dff 100644 --- a/FHEOffline/PairwiseMachine.cpp +++ b/FHEOffline/PairwiseMachine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseMachine.cpp diff --git a/FHEOffline/PairwiseMachine.h b/FHEOffline/PairwiseMachine.h index 8743a908..fd158297 100644 --- a/FHEOffline/PairwiseMachine.h +++ b/FHEOffline/PairwiseMachine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseMachine.h diff --git a/FHEOffline/PairwiseSetup.cpp b/FHEOffline/PairwiseSetup.cpp index fb89fa99..6bea0e80 100644 --- a/FHEOffline/PairwiseSetup.cpp +++ b/FHEOffline/PairwiseSetup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseSetup.cpp diff --git a/FHEOffline/PairwiseSetup.h b/FHEOffline/PairwiseSetup.h index 1b4e5f84..5de295ea 100644 --- a/FHEOffline/PairwiseSetup.h +++ b/FHEOffline/PairwiseSetup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PairwiseSetup.h diff --git a/FHEOffline/Player-Offline.h b/FHEOffline/Player-Offline.h index bc506f79..bf9144d0 100644 --- a/FHEOffline/Player-Offline.h +++ b/FHEOffline/Player-Offline.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Player-Offline.h diff --git a/FHEOffline/Producer.cpp b/FHEOffline/Producer.cpp index 7b09e9fd..0a116e00 100644 --- a/FHEOffline/Producer.cpp +++ b/FHEOffline/Producer.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Producer.cpp diff --git a/FHEOffline/Producer.h b/FHEOffline/Producer.h index f11705cc..8d6f7282 100644 --- a/FHEOffline/Producer.h +++ b/FHEOffline/Producer.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Producer.h diff --git a/FHEOffline/Proof.cpp b/FHEOffline/Proof.cpp index e459176c..5ca59675 100644 --- a/FHEOffline/Proof.cpp +++ b/FHEOffline/Proof.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Proof.cpp diff --git a/FHEOffline/Proof.h b/FHEOffline/Proof.h index f3517395..f9a73df2 100644 --- a/FHEOffline/Proof.h +++ b/FHEOffline/Proof.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Proof #define _Proof diff --git a/FHEOffline/Prover.cpp b/FHEOffline/Prover.cpp index 18deed5b..f0e26660 100644 --- a/FHEOffline/Prover.cpp +++ b/FHEOffline/Prover.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Prover.h" diff --git a/FHEOffline/Prover.h b/FHEOffline/Prover.h index 4cbecbdf..93d516a8 100644 --- a/FHEOffline/Prover.h +++ b/FHEOffline/Prover.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Prover #define _Prover diff --git a/FHEOffline/Reshare.cpp b/FHEOffline/Reshare.cpp index 4059003c..e6cbb898 100644 --- a/FHEOffline/Reshare.cpp +++ b/FHEOffline/Reshare.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHEOffline/Reshare.h" diff --git a/FHEOffline/Reshare.h b/FHEOffline/Reshare.h index 073c0d35..88ee914e 100644 --- a/FHEOffline/Reshare.h +++ b/FHEOffline/Reshare.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Reshare #define _Reshare diff --git a/FHEOffline/Sacrificing.cpp b/FHEOffline/Sacrificing.cpp index a22562fb..6592e95d 100644 --- a/FHEOffline/Sacrificing.cpp +++ b/FHEOffline/Sacrificing.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Checking.cpp diff --git a/FHEOffline/Sacrificing.h b/FHEOffline/Sacrificing.h index 6f0e4508..db842ec4 100644 --- a/FHEOffline/Sacrificing.h +++ b/FHEOffline/Sacrificing.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Checking.h diff --git a/FHEOffline/SimpleDistDecrypt.cpp b/FHEOffline/SimpleDistDecrypt.cpp index 20008b07..52c4869d 100644 --- a/FHEOffline/SimpleDistDecrypt.cpp +++ b/FHEOffline/SimpleDistDecrypt.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleDistDecrypt.cpp diff --git a/FHEOffline/SimpleDistDecrypt.h b/FHEOffline/SimpleDistDecrypt.h index d25c170b..87404de7 100644 --- a/FHEOffline/SimpleDistDecrypt.h +++ b/FHEOffline/SimpleDistDecrypt.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleDistDecrypt.h diff --git a/FHEOffline/SimpleEncCommit.cpp b/FHEOffline/SimpleEncCommit.cpp index cc389c5b..666fe3f2 100644 --- a/FHEOffline/SimpleEncCommit.cpp +++ b/FHEOffline/SimpleEncCommit.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleEncCommit.cpp diff --git a/FHEOffline/SimpleEncCommit.h b/FHEOffline/SimpleEncCommit.h index 3c466f13..bfeae5bc 100644 --- a/FHEOffline/SimpleEncCommit.h +++ b/FHEOffline/SimpleEncCommit.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleEncCommit.h diff --git a/FHEOffline/SimpleGenerator.cpp b/FHEOffline/SimpleGenerator.cpp index d074b286..a7a13452 100644 --- a/FHEOffline/SimpleGenerator.cpp +++ b/FHEOffline/SimpleGenerator.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleThread.cpp diff --git a/FHEOffline/SimpleGenerator.h b/FHEOffline/SimpleGenerator.h index c9802822..4c0e674d 100644 --- a/FHEOffline/SimpleGenerator.h +++ b/FHEOffline/SimpleGenerator.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleThread.h diff --git a/FHEOffline/SimpleMachine.cpp b/FHEOffline/SimpleMachine.cpp index 06253b0f..eb55de2d 100644 --- a/FHEOffline/SimpleMachine.cpp +++ b/FHEOffline/SimpleMachine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleMachine.cpp diff --git a/FHEOffline/SimpleMachine.h b/FHEOffline/SimpleMachine.h index 73a1d818..1ff1ea8c 100644 --- a/FHEOffline/SimpleMachine.h +++ b/FHEOffline/SimpleMachine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SimpleMachine.h diff --git a/FHEOffline/Verifier.cpp b/FHEOffline/Verifier.cpp index 277f4df8..038746f7 100644 --- a/FHEOffline/Verifier.cpp +++ b/FHEOffline/Verifier.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Verifier.h" diff --git a/FHEOffline/Verifier.h b/FHEOffline/Verifier.h index 0deebb46..059d48ba 100644 --- a/FHEOffline/Verifier.h +++ b/FHEOffline/Verifier.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Verifier #define _Verifier diff --git a/Fake-Offline.cpp b/Fake-Offline.cpp index c553529f..2127b2aa 100644 --- a/Fake-Offline.cpp +++ b/Fake-Offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/gf2n.h" diff --git a/GC/Access.h b/GC/Access.h new file mode 100644 index 00000000..b7e8a61c --- /dev/null +++ b/GC/Access.h @@ -0,0 +1,50 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Access.h + * + */ + +#ifndef GC_ACCESS_H_ +#define GC_ACCESS_H_ + +#include "Clear.h" + +namespace GC +{ + +template +class ReadAccess +{ +public: + T& dest; + const Clear address; + const int length; + + ReadAccess(T& dest, Clear address, int length, size_t& complexity) : + dest(dest), address(address), length(length) + { + complexity += length; + } +}; + +template +class WriteAccess +{ +public: + const T& source; + const Clear address; + + WriteAccess(Clear address, const T& source) : + source(source), address(address) {} +}; + +struct ClearWriteAccess +{ + const Clear address, value; + ClearWriteAccess(Clear address, Clear value) : address(address), value(value) {} +}; + +} /* namespace GC */ + +#endif /* GC_ACCESS_H_ */ diff --git a/GC/Clear.h b/GC/Clear.h new file mode 100644 index 00000000..9e3cf042 --- /dev/null +++ b/GC/Clear.h @@ -0,0 +1,31 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Clear.h + * + */ + +#ifndef GC_CLEAR_H_ +#define GC_CLEAR_H_ + +#include "Math/Integer.h" + +namespace GC +{ + +class Clear : public Integer +{ +public: + static string type_string() { return "clear"; } + + Clear() : Integer() {} + Clear(long a) : Integer(a) {} + Clear(const Integer& x) : Integer(x) {} + + void xor_(const Clear& x, const Clear& y) { a = x.a ^ y.a; } + void xor_(const Clear& x, long y) { a = x.a ^ y; } +}; + +} /* namespace GC */ + +#endif /* GC_CLEAR_H_ */ diff --git a/GC/FakeSecret.cpp b/GC/FakeSecret.cpp new file mode 100644 index 00000000..4206cec2 --- /dev/null +++ b/GC/FakeSecret.cpp @@ -0,0 +1,58 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Secret.cpp + * + */ + +#include + +namespace GC +{ + +int FakeSecret::default_length = 128; + +ostream& FakeSecret::out = cout; + +void FakeSecret::load(int n, const Integer& x) +{ + if ((size_t)n < 8 * sizeof(x) and abs(x.get()) >= (1LL << n)) + throw out_of_range("public value too long"); + *this = x; +} + +void FakeSecret::bitcom(Memory& S, const vector& regs) +{ + *this = 0; + for (unsigned int i = 0; i < regs.size(); i++) + *this ^= (S[regs[i]] << i); +} + +void FakeSecret::bitdec(Memory& S, const vector& regs) const +{ + for (unsigned int i = 0; i < regs.size(); i++) + S[regs[i]] = (*this >> i) & 1; +} + +void FakeSecret::load(vector >& accesses, + const Memory& mem) +{ + for (auto access : accesses) + access.dest = mem[access.address]; +} + +void FakeSecret::store(Memory& mem, + vector >& accesses) +{ + for (auto access : accesses) + mem[access.address] = access.source; +} + +void FakeSecret::store_clear_in_dynamic(Memory& mem, + const vector& accesses) +{ + for (auto access : accesses) + mem[access.address] = access.value; +} + +} /* namespace GC */ diff --git a/GC/FakeSecret.h b/GC/FakeSecret.h new file mode 100644 index 00000000..7ddb1390 --- /dev/null +++ b/GC/FakeSecret.h @@ -0,0 +1,77 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Secret.h + * + */ + +#ifndef GC_FAKESECRET_H_ +#define GC_FAKESECRET_H_ + +#include "GC/Clear.h" +#include "GC/Memory.h" +#include "GC/Access.h" + +#include "Math/Share.h" +#include "Math/gf2n.h" + +#include + +namespace GC +{ + +class FakeSecret : int128 +{ + __uint128_t a; + +public: + typedef FakeSecret DynamicType; + + static string type_string() { return "fake secret"; } + static string phase_name() { return "Faking"; } + + static int default_length; + + typedef ostream& out_type; + static ostream& out; + + static void store_clear_in_dynamic(Memory& mem, + const vector& accesses); + + static void load(vector< ReadAccess >& accesses, const Memory& mem); + static void store(Memory& mem, vector< WriteAccess >& accesses); + + template + static void andrs(T& processor, const vector& args) + { processor.andrs(args); } + + FakeSecret() : a(0) {} + FakeSecret(const Integer& x) : a(x.get()) {} + FakeSecret(__uint128_t x) : a(x) {} + + __uint128_t operator>>(const FakeSecret& other) const { return a >> other.a; } + __uint128_t operator<<(const FakeSecret& other) const { return a << other.a; } + + __uint128_t operator^=(const FakeSecret& other) { return a ^= other.a; } + + void load(int n, const Integer& x); + template + void load(int n, const Memory& mem, size_t address) { load(n, mem[address]); } + template + void store(Memory& mem, size_t address) { mem[address] = *this; } + + void bitcom(Memory& S, const vector& regs); + void bitdec(Memory& S, const vector& regs) const; + + template + void xor_(int n, const FakeSecret& x, const T& y) { (void)n; a = x.a ^ y.a; } + void andrs(int n, const FakeSecret& x, const FakeSecret& y) { (void)n; a = x.a * y.a; } + + void random_bit() { a = random() % 2; } + + void reveal(Clear& x) { x = a; } +}; + +} /* namespace GC */ + +#endif /* GC_FAKESECRET_H_ */ diff --git a/GC/Instruction.cpp b/GC/Instruction.cpp new file mode 100644 index 00000000..b519aaff --- /dev/null +++ b/GC/Instruction.cpp @@ -0,0 +1,228 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Instruction.cpp + * + */ + +#include + +#include "GC/Instruction.h" +#ifdef MAX_INLINE +#include "GC/Secret_inline.h" +#endif +#include "Processor/Instruction.h" +#include "BMR/Party.h" + +#include "Secret.h" +#include "Tools/parse.h" + +#include "GC/Instruction_inline.h" + +namespace GC +{ + +#define X(NAME, CODE) template bool NAME##_code(const Instruction& instruction, \ + Processor& processor) { (void)instruction; (void)processor; CODE; return true; } + INSTRUCTIONS +#undef X + +template +Instruction::Instruction() : + BaseInstruction() +{ + code = fallback_code; + size = 1; +} + +template +bool Instruction::get_offline_data_usage(int& usage) +{ + switch (opcode) + { + case ::USE: + usage += n; + return int(n) >= 0; + default: + return true; + } +} + +template +int Instruction::get_reg_type() const +{ + switch (opcode & 0x2F0) + { + case SECRET_WRITE: + return SBIT; + case CLEAR_WRITE: + return CBIT; + default: + switch (::BaseInstruction::get_reg_type()) + { + case ::INT: + return INT; + case ::MODP: + switch (opcode) + { + case LDMC: + return CBIT; + } + return SBIT; + } + return NONE; + } +} + +template +int GC::Instruction::get_max_reg(int reg_type) const +{ + int skip; + switch (opcode) + { + case LDMSD: + case LDMSDI: + skip = 3; + break; + case STMSD: + case STMSDI: + skip = 2; + break; + default: + return BaseInstruction::get_max_reg(reg_type); + } + + int m = 0; + if (reg_type == SBIT) + for (size_t i = 0; i < start.size(); i += skip) + m = max(m, start[i] + 1); + return m; +} + +template +int Instruction::get_mem(RegType reg_type) const +{ + int m = n + 1; + switch (opcode) + { + case LDMSD: + if (reg_type == DYN_SBIT) + { + m = 0; + for (size_t i = 0; i < start.size() / 3; i++) + m = max(m, start[3*i+1] + 1); + return m; + } + break; + case STMSD: + if (reg_type == DYN_SBIT) + { + m = 0; + for (size_t i = 0; i < start.size() / 2; i++) + m = max(m, start[2*i+1] + 1); + return m; + } + break; + case LDMS: + case STMS: + if (reg_type == SBIT) + return m; + break; + case LDMC: + case STMC: + if (reg_type == CBIT) + return m; + break; + case LDMINT: + case STMINT: + if (reg_type == INT) + return m; + break; + } + return 0; +} + +template +void Instruction::parse(istream& s, int pos) +{ + n = 0; + start.resize(0); + ::memset(r, 0, sizeof(r)); + + int file_pos = s.tellg(); + opcode = ::get_int(s); + + try { + parse_operands(s, pos); + } + catch (Invalid_Instruction& e) + { + int m; + switch (opcode) + { + case XORM: + n = get_int(s); + get_ints(r, s, 3); + break; + case XORCI: + case MULCI: + case LDBITS: + get_ints(r, s, 2); + n = get_int(s); + break; + case BITDECS: + case BITCOMS: + case BITDECC: + m = get_int(s) - 1; + get_ints(r, s, 1); + get_vector(m, start, s); + break; + case CONVCINT: + get_ints(r, s, 2); + break; + case REVEAL: + case CONVSINT: + n = get_int(s); + get_ints(r, s, 2); + break; + case LDMSDI: + case STMSDI: + case LDMSD: + case STMSD: + case STMSDCI: + case XORS: + case ANDRS: + get_vector(get_int(s), start, s); + break; + default: + ostringstream os; + os << "Invalid instruction " << showbase << hex << opcode + << " at " << dec << pos << "/" << hex << file_pos << dec; + throw Invalid_Instruction(os.str()); + } + } + + switch(opcode) + { +#define X(NAME, CODE) case NAME: \ + code = NAME##_code; \ + break; + INSTRUCTIONS +#undef X + default: + ostringstream os; + os << "Code not defined for instruction " << showbase << hex << opcode << dec; + throw Invalid_Instruction(os.str()); + break; + } +} + + + +template class Instruction; +template class Instruction< Secret >; +template class Instruction< Secret >; +template class Instruction< Secret >; +template class Instruction< Secret >; + +} /* namespace GC */ diff --git a/GC/Instruction.h b/GC/Instruction.h new file mode 100644 index 00000000..7a45c406 --- /dev/null +++ b/GC/Instruction.h @@ -0,0 +1,91 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Instruction.h + * + */ + +#ifndef PROCESSOR_GC_INSTRUCTION_H_ +#define PROCESSOR_GC_INSTRUCTION_H_ + +#include +#include +using namespace std; + +#include "GC/Processor.h" + +#include "Processor/Instruction.h" + +namespace GC +{ + +// Register types +enum RegType { + SBIT, + CBIT, + INT, + DYN_SBIT, + MAX_REG_TYPE, + NONE +}; + + +template +class Instruction : public ::BaseInstruction +{ + bool (*code)(const Instruction& instruction, Processor& processor); +public: + Instruction(); + + int get_r(int i) const { return r[i]; } + unsigned int get_n() const { return n; } + const vector& get_start() const { return start; } + int get_opcode() const { return opcode; } + + // Reads a single instruction from the istream + void parse(istream& s, int pos); + + // Return whether usage is known + bool get_offline_data_usage(int& usage); + + int get_reg_type() const; + + // Returns the maximal register used + int get_max_reg(int reg_type) const; + + // Returns the memory size used if applicable and known + int get_mem(RegType reg_type) const; + + // Execute this instruction + bool exe(Processor& processor) const { return code(*this, processor); } + bool execute(Processor& processor) const; +}; + +enum +{ + // GC specific + // write to secret + SECRET_WRITE = 0x200, + XORS = 0x200, + XORM = 0x201, + ANDRS = 0x202, + BITDECS = 0x203, + BITCOMS = 0x204, + CONVSINT = 0x205, + LDMSDI = 0x206, + STMSDI = 0x207, + LDMSD = 0x208, + STMSD = 0x209, + LDBITS = 0x20a, + // write to clear + CLEAR_WRITE = 0x210, + XORCI = 0x210, + BITDECC = 0x211, + CONVCINT = 0x213, + REVEAL = 0x214, + STMSDCI = 0x215, +}; + +} /* namespace GC */ + +#endif /* PROCESSOR_GC_INSTRUCTION_H_ */ diff --git a/GC/Instruction_inline.h b/GC/Instruction_inline.h new file mode 100644 index 00000000..252640c3 --- /dev/null +++ b/GC/Instruction_inline.h @@ -0,0 +1,56 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Instruction_inline.h + * + */ + +#ifndef GC_INSTRUCTION_INLINE_H_ +#define GC_INSTRUCTION_INLINE_H_ + +#ifdef MAX_INLINE +#define MAYBE_INLINE inline +#else +#define MAYBE_INLINE +#endif + +namespace GC { + +#include "instructions.h" + +template +inline bool fallback_code(const Instruction& instruction, Processor& processor) +{ + (void)processor; + cout << "Undefined instruction " << showbase << hex + << instruction.get_opcode() << endl << dec; + return true; +} + +template +MAYBE_INLINE bool Instruction::execute(Processor& processor) const +{ +#ifdef DEBUG_OPS + cout << typeid(T).name() << " "; + cout << "pc " << processor.PC << " op " << hex << showbase << opcode << " " + << dec << noshowbase << r[0]; + if (CommonParty::singleton) + cout << ", " << CommonParty::s().get_reg_size() << " regs "; + if (ProgramParty::singleton) + ProgramParty::s().print_input_size(); + cout << endl; +#endif + const Instruction& instruction = *this; + switch (opcode) + { +#define X(NAME, CODE) case NAME: CODE; return true; + INSTRUCTIONS +#undef X + default: + return fallback_code(*this, processor); + } +} + +} /* namespace GC */ + +#endif /* GC_INSTRUCTION_INLINE_H_ */ diff --git a/GC/Machine.cpp b/GC/Machine.cpp new file mode 100644 index 00000000..ba5bc100 --- /dev/null +++ b/GC/Machine.cpp @@ -0,0 +1,45 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Machine.cpp + * + */ + +#include + +#include "GC/Program.h" +#include "Secret.h" + +namespace GC +{ + +template +Machine::Machine(Memory& dynamic_memory) : MD(dynamic_memory) +{ + start_timer(); +} + +template +Machine::~Machine() +{ + for (auto it = timer.begin(); it != timer.end(); it++) + cout << T::phase_name() << " timer " << it->first << " at end: " + << it->second.elapsed() << " seconds" << endl; +} + +template +void Machine::reset(const Program& program) +{ + MS.resize(program.direct_mem(SBIT), "memory"); + MC.resize(program.direct_mem(CBIT), "memory"); + MI.resize(program.direct_mem(INT), "memory"); + MD.resize(program.direct_mem(DYN_SBIT), "dynamic memory"); +} + +template class Machine; +template class Machine< Secret >; +template class Machine< Secret >; +template class Machine< Secret >; +template class Machine< Secret >; + +} /* namespace GC */ diff --git a/GC/Machine.h b/GC/Machine.h new file mode 100644 index 00000000..d8114d41 --- /dev/null +++ b/GC/Machine.h @@ -0,0 +1,49 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Machine.h + * + */ + +#ifndef GC_MACHINE_H_ +#define GC_MACHINE_H_ + +#include +#include "GC/Clear.h" +#include "GC/Memory.h" + +#include "Math/Share.h" +#include "Math/gf2n.h" + +#include "Processor/Machine.h" + +#include +using namespace std; + +namespace GC +{ + +template class Program; + +template +class Machine : public ::BaseMachine +{ +public: + Memory MS; + Memory MC; + Memory MI; + Memory& MD; + + Machine(Memory& MD); + ~Machine(); + + void reset(const Program& program); + + void start_timer() { timer[0].start(); } + void stop_timer() { timer[0].stop(); } + void reset_timer() { timer[0].reset(); } +}; + +} /* namespace GC */ + +#endif /* GC_MACHINE_H_ */ diff --git a/GC/Memory.cpp b/GC/Memory.cpp new file mode 100644 index 00000000..6718511b --- /dev/null +++ b/GC/Memory.cpp @@ -0,0 +1,36 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Memory.cpp + * + */ + +#include + +#include "Math/Integer.h" + +#include "GC/Clear.h" +#include +#include "Secret.h" + +namespace GC +{ + +template +void Memory::resize(size_t size, const char* name) +{ + cout << "Resizing " << T::type_string() << " " << name << " to " << size << endl; + vector::resize(size); +} + +template class Memory; +template class Memory; +template class Memory; +template class Memory< Secret >; +template class Memory< Secret >; +template class Memory< Secret >; +template class Memory< Secret >; +template class Memory< AuthValue >; +template class Memory< SpdzShare >; + +} /* namespace GC */ diff --git a/GC/Memory.h b/GC/Memory.h new file mode 100644 index 00000000..358f3e61 --- /dev/null +++ b/GC/Memory.h @@ -0,0 +1,71 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Memory.h + * + */ + +#ifndef GC_MEMORY_H_ +#define GC_MEMORY_H_ + +#include +#include +#include +#include +using namespace std; + +#include "Exceptions/Exceptions.h" +#include "Clear.h" + +namespace GC +{ + +template +class Memory : public vector +{ +public: + void resize(size_t size, const char* name = ""); + void check_index(Integer index) const; + T& operator[] (Integer i); + const T& operator[] (Integer i) const; + + template + Memory& cast() { return *reinterpret_cast< Memory* >(this); } +}; + +template +inline void Memory::check_index(Integer index) const +{ + (void)index; +#ifdef CHECK_SIZE + size_t i = index.get(); + if (i >= vector::size()) + { + stringstream ss; + ss << "Memory overflow: " << i << "/" << vector::size(); + throw Processor_Error(ss.str()); + } +#endif +#ifdef DEBUG_MEMORY + cout << typeid(T).name() << " at " << this << " index " << i << ": " + << vector::operator[](i) << endl; +#endif +} + +template +inline T& Memory::operator[] (Integer i) +{ + check_index(i); + return vector::operator[](i.get()); +} + +template +inline const T& Memory::operator[] (Integer i) const +{ + check_index(i); + return vector::operator[](i.get()); +} + +} /* namespace GC */ + +#endif /* GC_MEMORY_H_ */ diff --git a/GC/Processor.cpp b/GC/Processor.cpp new file mode 100644 index 00000000..565dd393 --- /dev/null +++ b/GC/Processor.cpp @@ -0,0 +1,191 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Processor.cpp + * + */ + +#include + +#include +using namespace std; + +#include "GC/Program.h" +#include "Secret.h" +#include "Access.h" + +namespace GC +{ + +template +Processor* Processor::singleton = 0; + +template +Processor& Processor::s() +{ + if (singleton == 0) + throw runtime_error("no singleton"); + return *singleton; +} + +template +Processor::Processor(Machine& machine) : + machine(machine), PC(0), time(0), + complexity(0) +{ + if (singleton) + throw runtime_error("there can only be one"); + singleton = this; +} + +template +Processor::~Processor() +{ + cout << "Finished after " << time << " instructions" << endl; +} + +template +void Processor::reset(const Program& program) +{ + S.resize(program.num_reg(SBIT), "registers"); + C.resize(program.num_reg(CBIT), "registers"); + I.resize(program.num_reg(INT), "registers"); + machine.reset(program); +} + +template +void Processor::bitdecc(const vector& regs, const Clear& x) +{ + for (unsigned int i = 0; i < regs.size(); i++) + C[regs[i]] = (x >> i) & 1; +} + +template +void Processor::bitdecint(const vector& regs, const Integer& x) +{ + for (unsigned int i = 0; i < regs.size(); i++) + I[regs[i]] = (x >> i) & 1; +} + +template +void GC::Processor::load_dynamic_direct(const vector& args) +{ + vector< ReadAccess > accesses; + if (args.size() % 3 != 0) + throw runtime_error("invalid number of arguments"); + for (size_t i = 0; i < args.size(); i += 3) + accesses.push_back({S[args[i]], args[i+1], args[i+2], complexity}); + T::load(accesses, machine.MD); +} + +template +void GC::Processor::load_dynamic_indirect(const vector& args) +{ + vector< ReadAccess > accesses; + if (args.size() % 3 != 0) + throw runtime_error("invalid number of arguments"); + for (size_t i = 0; i < args.size(); i += 3) + accesses.push_back({S[args[i]], C[args[i+1]], args[i+2], complexity}); + T::load(accesses, machine.MD); +} + +template +void GC::Processor::store_dynamic_direct(const vector& args) +{ + vector< WriteAccess > accesses; + if (args.size() % 2 != 0) + throw runtime_error("invalid number of arguments"); + for (size_t i = 0; i < args.size(); i += 2) + accesses.push_back({args[i+1], S[args[i]]}); + T::store(machine.MD, accesses); + complexity += accesses.size() / 2 * T::default_length; +} + +template +void GC::Processor::store_dynamic_indirect(const vector& args) +{ + vector< WriteAccess > accesses; + if (args.size() % 2 != 0) + throw runtime_error("invalid number of arguments"); + for (size_t i = 0; i < args.size(); i += 2) + accesses.push_back({C[args[i+1]], S[args[i]]}); + T::store(machine.MD, accesses); + complexity += accesses.size() / 2 * T::default_length; +} + +void check_args(const vector& args, int n) +{ + if (args.size() % n != 0) + throw runtime_error("invalid number of arguments"); +} + +template +void GC::Processor::store_clear_in_dynamic(const vector& args) +{ + vector accesses; + check_args(args, 2); + for (size_t i = 0; i < args.size(); i += 2) + accesses.push_back({C[args[i+1]], C[args[i]]}); + T::store_clear_in_dynamic(machine.MD, accesses); +} + +template +void Processor::xors(const vector& args) +{ + check_args(args, 4); + for (size_t i = 0; i < args.size(); i += 4) + { + S[args[i+1]].xor_(args[i], S[args[i+2]], S[args[i+3]]); +#ifndef FREE_XOR + complexity += args[i]; +#endif + } +} + +template +void Processor::andrs(const vector& args) +{ + check_args(args, 4); + for (size_t i = 0; i < args.size(); i += 4) + { + S[args[i+1]].andrs(args[i], S[args[i+2]], S[args[i+3]]); + complexity += args[i]; + } +} + +template +void Processor::print_reg(int reg, int n) +{ +#ifdef DEBUG_VALUES + cout << "print_reg " << typeid(T).name() << " " << reg << " " << &C[reg] << endl; +#endif + T::out << "Reg[" << reg << "] = " << hex << showbase << C[reg] << dec << " # "; + print_str(n); + T::out << endl << flush; +} + +template +void Processor::print_reg_plain(Clear& value) +{ + T::out << hex << showbase << value << dec << flush; +} + +template +void Processor::print_chr(int n) +{ + T::out << (char)n << flush; +} + +template +void Processor::print_str(int n) +{ + T::out << string((char*)&n,sizeof(n)) << flush; +} + +template class Processor; +template class Processor< Secret >; +template class Processor< Secret >; +template class Processor< Secret >; +template class Processor< Secret >; + +} /* namespace GC */ diff --git a/GC/Processor.h b/GC/Processor.h new file mode 100644 index 00000000..938330c3 --- /dev/null +++ b/GC/Processor.h @@ -0,0 +1,84 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Processor.h + * + */ + +#ifndef GC_PROCESSOR_H_ +#define GC_PROCESSOR_H_ + +#include +using namespace std; + +#include "GC/Clear.h" +#include +#include "GC/Machine.h" + +#include "Math/Integer.h" +#include "Processor/Processor.h" + +namespace GC +{ + +template class Program; + +template +class Processor : public ::ProcessorBase +{ + static Processor* singleton; +public: + static Processor& s(); + static int get_PC(); + + Machine& machine; + + unsigned int PC; + unsigned int time; + + // rough measure for the memory usage + size_t complexity; + + Memory S; + Memory C; + Memory I; + + Processor(Machine& machine); + ~Processor(); + + void reset(const Program& program); + + void bitcoms(T& x, const vector& regs) { x.bitcom(S, regs); } + void bitdecs(const vector& regs, const T& x) { x.bitdec(S, regs); } + void bitdecc(const vector& regs, const Clear& x); + void bitdecint(const vector& regs, const Integer& x); + + void random_bit(T &x) { x.random_bit(); } + + void load_dynamic_direct(const vector& args); + void store_dynamic_direct(const vector& args); + void load_dynamic_indirect(const vector& args); + void store_dynamic_indirect(const vector& args); + void store_clear_in_dynamic(const vector& args); + + void xors(const vector& args); + void andrs(const vector& args); + + void print_reg(int reg, int n); + void print_reg_plain(Clear& value); + void print_chr(int n); + void print_str(int n); +}; + +template +int Processor::get_PC() +{ + if (singleton) + return singleton->PC; + else + return -1; +} + +} /* namespace GC */ + +#endif /* GC_PROCESSOR_H_ */ diff --git a/GC/Program.cpp b/GC/Program.cpp new file mode 100644 index 00000000..1c110fa7 --- /dev/null +++ b/GC/Program.cpp @@ -0,0 +1,124 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Program.cpp + * + */ + +#include + +#include "Secret.h" + +#include + +#ifdef MAX_INLINE +#include "Instruction_inline.h" +#endif + +namespace GC +{ + +template +Program::Program() : + offline_data_used(0), unknown_usage(false) +{ + compute_constants(); +} + +template +void Program::compute_constants() +{ + for (int reg_type = 0; reg_type < MAX_REG_TYPE; reg_type++) + { + max_reg[reg_type] = 0; + max_mem[reg_type] = 0; + } + for (unsigned int i = 0; i < p.size(); i++) + { + if (!p[i].get_offline_data_usage(offline_data_used)) + unknown_usage = true; + for (int reg_type = 0; reg_type < MAX_REG_TYPE; reg_type++) + { + max_reg[reg_type] = max(max_reg[reg_type], + p[i].get_max_reg(RegType(reg_type))); + max_mem[reg_type] = max(max_mem[reg_type], + p[i].get_mem(RegType(reg_type))); + } + } +} + +template +void Program::parse(istream& s) +{ + p.resize(0); + Instruction instr; + s.peek(); + int pos = 0; + CALLGRIND_STOP_INSTRUMENTATION; + while (!s.eof()) + { + instr.parse(s, pos); + p.push_back(instr); + //cerr << "\t" << instr << endl; + s.peek(); + pos++; + } + CALLGRIND_START_INSTRUMENTATION; + compute_constants(); +} + +template +void Program::print_offline_cost() const +{ + if (unknown_usage) + { + cerr << "Tape has unknown usage" << endl; + return; + } + + cerr << "Cost of first tape: " << offline_data_used << endl; +} + +template +__attribute__((flatten)) +BreakType Program::execute(Processor& Proc, int PC) const +{ + if (PC != -1) + Proc.PC = PC; +#ifdef DEBUG_ROUNDS + cout << typeid(T).name() << " starting at PC " << Proc.PC << endl; +#endif + unsigned int size = p.size(); + size_t time = Proc.time; + Proc.complexity = 0; + do + { +#ifdef DEBUG_EXE + cout << "execute " << time << "/" << Proc.PC << endl; +#endif + if (Proc.PC >= size) + { + Proc.time = time; + return DONE_BREAK; + } + p[Proc.PC++].execute(Proc); + time++; +#ifdef DEBUG_COMPLEXITY + cout << "complexity at " << time << ": " << Proc.complexity << endl; +#endif + } + while (Proc.complexity < (1 << 20)); + Proc.time = time; +#ifdef DEBUG_ROUNDS + cout << "breaking at time " << Proc.time << endl; +#endif + return TIME_BREAK; +} + +template class Program; +template class Program< Secret >; +template class Program< Secret >; +template class Program< Secret >; +template class Program< Secret >; + +} /* namespace GC */ diff --git a/GC/Program.h b/GC/Program.h new file mode 100644 index 00000000..b0cebe05 --- /dev/null +++ b/GC/Program.h @@ -0,0 +1,75 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Program.h + * + */ + +#ifndef GC_PROGRAM_H_ +#define GC_PROGRAM_H_ + +#include "GC/Instruction.h" + +#include +using namespace std; + +namespace GC +{ + +enum BreakType { + TIME_BREAK, + DONE_BREAK, + CAP_BREAK, +}; + +template class Processor; + +template +class Program +{ + vector< Instruction > p; + int offline_data_used; + + // Maximal register used + int max_reg[MAX_REG_TYPE]; + + // Memory size used directly + int max_mem[MAX_REG_TYPE]; + + // True if program contains variable-sized loop + bool unknown_usage; + + void compute_constants(); + + public: + + Program(); + + // Read in a program + void parse(istream& s); + + int get_offline_data_used() const { return offline_data_used; } + void print_offline_cost() const; + + bool usage_unknown() const { return unknown_usage; } + + int num_reg(RegType reg_type) const + { return max_reg[reg_type]; } + + int direct_mem(RegType reg_type) const + { return max_mem[reg_type]; } + + // Execute this program, updateing the processor and memory + // and streams pointing to the triples etc + BreakType execute(Processor& Proc, int PC = -1) const; + + bool done(Processor& Proc) const { return Proc.PC >= p.size(); } + + template + Program& cast() { return *reinterpret_cast< Program* >(this); } +}; + + +} /* namespace GC */ + +#endif /* GC_PROGRAM_H_ */ diff --git a/GC/Secret.cpp b/GC/Secret.cpp new file mode 100644 index 00000000..940ce97e --- /dev/null +++ b/GC/Secret.cpp @@ -0,0 +1,418 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * EvalSecret.cpp + * + */ + +#include "BMR/CommonParty.h" +#include "BMR/Party.h" +#include "BMR/Register_inline.h" + +#include "Secret.h" +#include "Secret_inline.h" + +namespace GC +{ + +template +int Secret::default_length = 128; + +template +typename T::out_type Secret::out = T::out; + +void AuthValue::assign(const word& value, const int128& mac_key, bool not_first_player) +{ + if (not_first_player) + share = 0; + else + share = value; + mac = _mm_clmulepi64_si128(_mm_cvtsi64_si128(mac_key.get_lower()), _mm_cvtsi64_si128(value), 0); +} + +ostream& operator<<(ostream& o, const AuthValue& auth_value) +{ + o << hex << auth_value.share << " " << auth_value.mac; + return o; +} + +template +Secret Secret::input(party_id_t from, const int128& input, int n_bits) +{ + Secret res; + if (n_bits < 0) + n_bits = default_length; + for (int i = 0; i < n_bits; i++) + { + res.get_new_reg().input(from, input.get_bit(i)); +#ifdef DEBUG_INPUT + cout << (int)input.get_bit(i); +#endif + } +#ifdef DEBUG_INPUT + cout << endl; +#endif + if ((size_t)n_bits != res.registers.size()) + { + cout << n_bits << " " << res.registers.size() << endl; + throw runtime_error("wrong bit length in input()"); + } +#ifdef DEBUG_INPUT + int128 a; + res.reveal(a); + cout << " input " << hex << a << "(" << res.size() << ") from " << from + << " (" << input << ", " << dec << n_bits << ")" << endl; +#endif + return res; +} + +template +void Secret::random(int n_bits, int128 share) +{ + (void)share; + if (n_bits > 128) + throw not_implemented(); +#ifdef NO_INPUT + resize_regs(n_bits); + for (int i = 0; i < n_bits; i++) + get_reg(i).random(); +#else + for (int i = 0; i < CommonParty::singleton->get_n_parties(); i++) + { + Secret tmp = *this; + Secret s = input(i + 1, share, n_bits); + *this = tmp + s; +#ifdef DEBUG_DYNAMIC + int128 a,b,c; + tmp.reveal(a); + s.reveal(b); + reveal(c); + cout << c << " = " << a << " ^ " << b << " (" << dec << n_bits << ", " << share << ")" << endl; +#endif + } +#endif +#ifdef DEBUG_RANDOM + int128 revealed; + reveal(revealed); + cout << "random " << revealed << " share " << share << endl; +#endif + if ((size_t)n_bits != registers.size()) + { + cout << n_bits << " " << registers.size() << endl; + throw runtime_error("wrong bit length in random()"); + } +} + +template +void Secret::random_bit() +{ + return random(1, CommonParty::s().prng.get_uchar() & 1); +} + +template +Secret Secret::reconstruct(const int128& x, int length) +{ + Secret res; + for (int i = 0; i < CommonParty::singleton->get_n_parties(); i++) + { + Secret tmp = res; + Secret share = input(i + 1, x, length); + res = share + tmp; +#ifdef DEBUG_DYNAMIC + int128 a,b,c; + tmp.reveal(a); + share.reveal(b); + res.reveal(c); + cout << hex << c << "(" << dec << res.size() << ") = " << hex << a + << "(" << dec << tmp.size() << ")" << " ^ " << hex << b << "(" + << dec << share.size() << ") (" << dec << x << ", " << dec + << length << ")" << endl; +#endif + } + return res; + if ((size_t)length != res.registers.size()) + { + cout << length << " " << res.registers.size() << endl; + throw runtime_error("wrong bit length in reconstruct()"); + } +} + +template +void Secret::store(Memory& mem, size_t address) +{ + AuthValue& dest = mem[address]; + Secret mac_key = reconstruct(CommonParty::s().get_mac_key().get(), default_length); + Secret mac, mask, mac_mask; + mac = carryless_mult(*this, mac_key); + GC::Mask mask_share; + int length = registers.size(); + int mac_length = mac.registers.size(); + T::get_dyn_mask(mask_share, length, mac_length); + mask.random(length, mask_share.share); + mac_mask.random(mac_length, mask_share.mac); + word masked; + int128 masked_mac; + (*this + mask).reveal(masked); + (mac + mac_mask).reveal(masked_mac); +#ifdef DEBUG_DYNAMIC + word a,b; + int128 c,d; + reveal(a); + mask.reveal(b); + mac.reveal(c); + mac_mask.reveal(d); + cout << masked << " = " << a << " ^ " << b << endl; + cout << masked_mac << " = " << c << " ^ " << d << endl; +#endif + T::unmask(dest, mask_share.share, mask_share.mac, masked, masked_mac); +} + +template +void Secret::store(Memory& mem, + vector > >& accesses) +{ + T::store(mem, accesses); +} + +template +void Secret::output(Register& reg) +{ + cast(reg).output(); +} + +template +Secret Secret::carryless_mult(const Secret& x, const Secret& y) +{ + Secret res; + if (x.registers.size() == 0) + throw not_implemented(); +#ifdef DEBUG_DYNAMIC2 + for (int i = 0; i < x.registers.size(); i++) + output(x.registers[i]); + for (int i = 0; i < y.registers.size(); i++) + output(y.registers[i]); +#endif + for (size_t i = 0; i < x.registers.size() + y.registers.size() - 1; i++) + { + int start = max((size_t)0, i - y.registers.size() + 1); + int stop = min(i + 1, x.registers.size()); + Register sum = AND(x.get_reg(start), y.get_reg(i - start)); +#ifdef DEBUG_DYNAMIC2 + output(sum); + cout << "carryless " << i << " " << start << " " << i - start << + " sum " << (int)cast(sum).get_output() << + " x " << (int)x.get_reg(start).get_output() << + " y " << (int)y.get_reg(i - start).get_output() << + " sum id " << sum.get_reg().get_id() << endl; +#endif + for (int j = start + 1; j < stop; j++) + { + Register product = AND(x.get_reg(j), y.get_reg(i - j)); + sum = XOR(sum, product); +#ifdef DEBUG_DYNAMIC2 + cout << "carryless " << + " prod id " << product.get_reg().get_id() << + " sum id " << sum.get_reg().get_id() << endl << flush; + output(product); + output(sum); + cout << "carryless " << i << " " << j << " " << i - j << + " prod " << (int)cast(product).get_output() << + " sum " << (int)cast(sum).get_output() << + " x " << (int)x.get_reg(j).get_output() << + " y " << (int)y.get_reg(i - j).get_output() << endl; +#endif + } + res.registers.push_back(sum); + } +#ifdef DEBUG_DYNAMIC + word a, b; + int128 c; + x.reveal(a); + y.reveal(b); + res.reveal(c); + cout << typeid(T).name() << endl; + cout << c << " = " << hex << a << " * " << b << endl; + AuthValue d; + d.assign(a, b, false); + if (d.mac != c) + throw runtime_error("carryless mult"); +#endif + return res; +} + +template +Secret::Secret() +{ + +} + +template +T& GC::Secret::get_reg(int i) +{ + return *reinterpret_cast(®isters.at(i)); +} + +template +const T& GC::Secret::get_reg(int i) const +{ + return *reinterpret_cast(®isters.at(i)); +} + + +template +T& GC::Secret::get_new_reg() +{ + registers.push_back(T::new_reg()); + T &res = cast(registers.back()); +#ifdef DEBUG_REGS + cout << "Secret: new " << typeid(T).name() << " " << res.get_id() << " at " << &res << endl; +#endif + return res; +} + +template +void Secret::load(int n, const Integer& x) +{ + if ((unsigned)n < 8 * sizeof(x) and abs(x.get()) > (1LL << n)) + throw out_of_range("public value too long"); +#ifdef DEBUG_ROUNDS2 + cout << "secret from integer " << hex << this << dec << " " << endl; +#endif + resize_regs(n); + for (int i = 0; i < n; i++) + { + get_reg(i).public_input((x.get() >> i) & 1); + } +#ifdef DEBUG_VALUES + cout << "input " << x << endl; + for (int i = 0; i < n; i++) + cout << ((x.get() >> i) & 1); + cout << endl; + cout << "on registers: " << endl; + for (int i = 0; i < n; i++) + cout << get_reg(i).get_id() << " "; + cout << endl; +#endif +} + +template +void Secret::load(int n, const Memory& mem, size_t address) +{ + (void)n; + const AuthValue& x = mem[address]; + *this = reconstruct(x.share, default_length); + Secret mac, check_mac, mac_key; + mac = reconstruct(x.mac, 2 * default_length); + mac_key = reconstruct(CommonParty::s().get_mac_key().get(), default_length); + check_mac = carryless_mult(*this, mac_key); + int128 result; + (mac + check_mac).reveal(result); +#ifdef DEBUG_DYNAMIC + cout << "loading " << hex << x.share << " " << x.mac << endl; + int128 a; + mac.reveal(a); + word b; + reveal(b); + cout << "stored value " << hex << b << " mac " << a << endl; +#endif + T::check(result, x.share, x.mac); +} + +template +void Secret::load(vector > >& accesses, const Memory& mem) +{ + for (auto&& access : accesses) + { + int n = access.length; + if (n <= 0 || n > default_length) + throw runtime_error("invalid length for dynamic loading"); + access.dest.resize_regs(n); + } + T::load(accesses, mem); +} + +template +Secret Secret::operator<<(int i) +{ + Secret res; + for (int j = 0; j < i; j++) + res.get_new_reg().public_input(0); + res.registers.insert(res.registers.end(), registers.begin(), + registers.end()); + return res; +} + +template +Secret Secret::operator>>(int i) +{ + Secret res; + res.registers.insert(res.registers.end(), registers.begin() + i, registers.end()); + return res; +} + +template +void Secret::bitcom(Memory& S, const vector& regs) +{ + registers.clear(); + for (unsigned int i = 0; i < regs.size(); i++) + { + if (S[regs[i]].registers.size() != 1) + throw Processor_Error("can only compose bits"); + registers.push_back(S[regs[i]].registers.at(0)); + } +} + +template +void Secret::bitdec(Memory& S, const vector& regs) const +{ + if (regs.size() > registers.size()) + throw out_of_range("not enough bits for bit decomposition"); + for (unsigned int i = 0; i < regs.size(); i++) + { + Secret& secret = S[regs[i]]; + secret.registers.clear(); + secret.registers.push_back(registers.at(i)); + } +} + +template +template +void Secret::reveal(U& x) +{ +#ifdef DEBUG_OUTPUT + cout << "output: "; +#endif + x = 0; + for (unsigned int i = 0; i < min(8 * sizeof(U), registers.size()); i++) + { + get_reg(i).output(); + char out = get_reg(i).get_output(); + x ^= U(out) << i; +#ifdef DEBUG_OUTPUT + cout << (int)out; +#endif + } +#ifdef DEBUG_OUTPUT + cout << endl; +#endif +#ifdef DEBUG_VALUES + cout << typeid(T).name() << " " << &x << endl; + cout << "reveal " << registers.size() << " bits: " << hex << showbase << x << dec << endl; + cout << "from registers:" << endl; + for (unsigned int i = 0; i < registers.size(); i++) + cout << registers[i].get_id() << " "; + cout << endl; +#endif +} + +template class Secret; +template class Secret; +template class Secret; +template class Secret; + +template void Secret::reveal(Clear& x); +template void Secret::reveal(Clear& x); +template void Secret::reveal(Clear& x); +template void Secret::reveal(Clear& x); + +} /* namespace GC */ diff --git a/GC/Secret.h b/GC/Secret.h new file mode 100644 index 00000000..7ef1e939 --- /dev/null +++ b/GC/Secret.h @@ -0,0 +1,132 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * EvalSecret.h + * + */ + +#ifndef GC_SECRET_H_ +#define GC_SECRET_H_ + +#include "BMR/Register.h" +#include "BMR/CommonParty.h" +#include "BMR/AndJob.h" + +#include "GC/Clear.h" +#include "GC/Memory.h" +#include "GC/Access.h" + +#include "Math/Share.h" + +namespace GC +{ + +class AuthValue +{ +public: + static string type_string() { return "authenticated value"; } + word share; + int128 mac; + AuthValue() : share(0), mac(0) {} + void assign(const word& value, const int128& mac_key, bool first_player); + void check(const word& mac_key) const; + friend ostream& operator<<(ostream& o, const AuthValue& auth_value); +}; + +class Mask +{ +public: + word share; + int128 mac; + Mask() : share(0) {} +}; + +class SpdzShare : public Share +{ +public: + void assign(const gf2n& value, const gf2n& mac_key, bool first_player) + { Share::assign(value, first_player ? 0 : 1, mac_key); } +}; + +template +class Secret +{ + CheckVector registers; + + T& get_new_reg(); + +public: +#ifdef SPDZ_AUTH + typedef SpdzShare DynamicType; +#else + typedef AuthValue DynamicType; +#endif + + static string type_string() { return "evaluation secret"; } + static string phase_name() { return T::name(); } + + static int default_length; + + static typename T::out_type out; + + static T& cast(Register& reg) { return *reinterpret_cast(®); } + static const T& cast(const Register& reg) { return *reinterpret_cast(®); } + + static Secret input(party_id_t from, const int128& input, int n_bits = -1); + void random(int n_bits, int128 share); + void random_bit(); + static Secret reconstruct(const int128& x, int length); + template + static void store_clear_in_dynamic(U& mem, const vector& accesses) + { T::store_clear_in_dynamic(mem, accesses); } + void store(Memory& mem, size_t address); + static Secret carryless_mult(const Secret& x, const Secret& y); + static void output(Register& reg); + + static void load(vector< ReadAccess< Secret > >& accesses, const Memory& mem); + static void store(Memory& mem, vector< WriteAccess< Secret > >& accesses); + + static void andrs(Processor< Secret >& processor, const vector& args) + { T::andrs(processor, args); } + + Secret(); + Secret(const Integer& x) { *this = x; } + + void load(int n, const Integer& x); + void operator=(const Integer& x) { load(default_length, x); } + void load(int n, const Memory& mem, size_t address); + + Secret operator<<(int i); + Secret operator>>(int i); + + void bitcom(Memory< Secret >& S, const vector& regs); + void bitdec(Memory< Secret >& S, const vector& regs) const; + + Secret operator+(const Secret x) const; + Secret& operator+=(const Secret x) { *this = *this + x; return *this; } + + void xor_(int n, const Secret& x, const Secret& y); + void andrs(int n, const Secret& x, const Secret& y); + + template + void reveal(U& x); + + int size() const { return registers.size(); } + CheckVector& get_regs() { return registers; } + const CheckVector& get_regs() const { return registers; } + + const T& get_reg(int i) const; + T& get_reg(int i); + void resize_regs(int n) { registers.resize(n, T::new_reg()); } +}; + +template +inline ostream& operator<<(ostream& o, Secret& secret) +{ + o << "(" << secret.size() << " secret bits)"; + return o; +} + +} /* namespace GC */ + +#endif /* GC_SECRET_H_ */ diff --git a/GC/Secret_inline.h b/GC/Secret_inline.h new file mode 100644 index 00000000..075506c3 --- /dev/null +++ b/GC/Secret_inline.h @@ -0,0 +1,99 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Secret_inline.h + * + */ + +#ifndef GC_SECRET_INLINE_H_ +#define GC_SECRET_INLINE_H_ + +#ifdef MAX_INLINE +#define MAYBE_INLINE inline +#else +#define MAYBE_INLINE +#endif + +#include "BMR/Register_inline.h" + +namespace GC { + +template +inline void XOR(Register& res, const Register& left, const Register& right) +{ +#ifdef FREE_XOR + Secret::cast(res).XOR(Secret::cast(left), Secret::cast(right)); +#else + Secret::cast(res).op(Secret::cast(left), Secret::cast(right), 0x0110); +#endif +} + +template +inline Register XOR(const Register& left, const Register& right) +{ + Register res(T::new_reg()); + XOR(res, left, right); + return res; +} + +template +inline void AND(Register& res, const Register& left, const Register& right) +{ +#ifdef KEY_SIGNAL +#ifdef DEBUG_REGS + cout << "*" << res.get_id() << " = AND(*" << left.get_id() << ",*" << right.get_id() << ")" << endl; +#endif +#else +#endif + Secret::cast(res).op(Secret::cast(left), Secret::cast(right), 0x0001); +} + +template +inline Register AND(const Register& left, const Register& right) +{ + Register res = T::new_reg(); + AND(res, left, right); + return res; +} + +template +inline Secret GC::Secret::operator+(const Secret x) const +{ + Secret res; + res.xor_(max(registers.size(), x.registers.size()), *this, x); + return res; +} + +template +MAYBE_INLINE void Secret::xor_(int n, const Secret& x, const Secret& y) +{ + int min_n = min((size_t)n, min(x.registers.size(), y.registers.size())); + resize_regs(min_n); + for (int i = 0; i < min_n; i++) + { + XOR(registers[i], x.get_reg(i), y.get_reg(i)); + } + + if (min_n < n) + { + const vector* more_regs; + if (y.registers.size() < x.registers.size()) + more_regs = &x.registers; + else + more_regs = &y.registers; + registers.insert(registers.end(), more_regs->begin() + min_n, + more_regs->begin() + min((size_t)n, more_regs->size())); + } +} + +template +MAYBE_INLINE void Secret::andrs(int n, const Secret& x, const Secret& y) +{ + resize_regs(n); + for (int i = 0; i < n; i++) + AND(registers[i], x.get_reg(i), y.get_reg(0)); +} + +} /* namespace GC */ + +#endif /* GC_SECRET_INLINE_H_ */ diff --git a/GC/instructions.h b/GC/instructions.h new file mode 100644 index 00000000..eef212d6 --- /dev/null +++ b/GC/instructions.h @@ -0,0 +1,111 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * instructions.h + * + */ + +#ifndef GC_INSTRUCTIONS_H_ +#define GC_INSTRUCTIONS_H_ + +#include + +#define P processor +#define INST instruction +#define M processor.machine + +#define R0 instruction.get_r(0) +#define R1 instruction.get_r(1) +#define R2 instruction.get_r(2) + +#define S0 processor.S[instruction.get_r(0)] +#define S1 processor.S[instruction.get_r(1)] +#define S2 processor.S[instruction.get_r(2)] + +#define C0 processor.C[instruction.get_r(0)] +#define C1 processor.C[instruction.get_r(1)] +#define C2 processor.C[instruction.get_r(2)] + +#define I0 processor.I[instruction.get_r(0)] +#define I1 processor.I[instruction.get_r(1)] +#define I2 processor.I[instruction.get_r(2)] + +#define N instruction.get_n() +#define EXTRA instruction.get_start() + +#define MSD M.MS[N] +#define MC M.MC[N] +#define MID M.MI[N] + +#define MSI M.MS[I1.get()] +#define MII M.MI[I1.get()] + +#define MD M.MD + +#define INSTRUCTIONS \ + X(XORS, P.xors(EXTRA)) \ + X(XORC, C0.xor_(C1, C2)) \ + X(XORCI, C0.xor_(C1, N)) \ + X(ANDRS, T::andrs(P, EXTRA)) \ + X(ADDC, C0 = C1 + C2) \ + X(ADDCI, C0 = C1 + N) \ + X(MULCI, C0 = C1 * N) \ + X(BITDECS, P.bitdecs(EXTRA, S0)) \ + X(BITCOMS, P.bitcoms(S0, EXTRA)) \ + X(BITDECC, P.bitdecc(EXTRA, C0)) \ + X(BITDECINT, P.bitdecint(EXTRA, I0)) \ + X(SHRCI, C0 = C1 >> N) \ + X(LDBITS, S0.load(R1, N)) \ + X(LDMS, S0 = MSD) \ + X(STMS, MSD = S0) \ + X(LDMSI, S0 = MSI) \ + X(STMSI, MSI = S0) \ + X(LDMC, C0 = MC) \ + X(STMC, MC = C0) \ + X(LDMSD, P.load_dynamic_direct(EXTRA)) \ + X(STMSD, P.store_dynamic_direct(EXTRA)) \ + X(LDMSDI, P.load_dynamic_indirect(EXTRA)) \ + X(STMSDI, P.store_dynamic_indirect(EXTRA)) \ + X(STMSDCI, P.store_clear_in_dynamic(EXTRA)) \ + X(CONVSINT, S0.load(N, I1)) \ + X(CONVCINT, C0 = I1) \ + X(MOVS, S0 = S1) \ + X(BIT, P.random_bit(S0)) \ + X(REVEAL, S1.reveal(C0)) \ + X(PRINTREG, P.print_reg(R0, N)) \ + X(PRINTREGPLAIN, P.print_reg_plain(C0)) \ + X(PRINTCHR, P.print_chr(N)) \ + X(PRINTSTR, P.print_str(N)) \ + X(LDINT, I0 = int(N)) \ + X(ADDINT, I0 = I1 + I2) \ + X(SUBINT, I0 = I1 - I2) \ + X(MULINT, I0 = I1 * I2) \ + X(DIVINT, I0 = I1 / I2) \ + X(JMP, P.PC += N) \ + X(JMPNZ, if (I0 != 0) P.PC += N) \ + X(JMPEQZ, if (I0 == 0) P.PC += N) \ + X(EQZC, I0 = I1 == 0) \ + X(LTZC, I0 = I1 < 0) \ + X(LTC, I0 = I1 < I2) \ + X(GTC, I0 = I1 > I2) \ + X(EQC, I0 = I1 == I2) \ + X(JMPI, P.PC += I0) \ + X(LDMINT, I0 = MID) \ + X(STMINT, MID = I0) \ + X(LDMINTI, I0 = MII) \ + X(STMINTI, MII = I0) \ + X(PUSHINT, P.pushi(I0.get())) \ + X(POPINT, long x; P.popi(x); I0 = x) \ + X(MOVINT, I0 = I1) \ + X(LDARG, I0 = P.get_arg()) \ + X(STARG, P.set_arg(I0.get())) \ + X(TIME, M.time()) \ + X(START, M.start(N)) \ + X(STOP, M.stop(N)) \ + X(GLDMS, ) \ + X(GLDMC, ) \ + X(PRINTINT, S0.out << I0) \ + X(STARTGRIND, CALLGRIND_START_INSTRUMENTATION) \ + X(STOPGRIND, CALLGRIND_STOP_INSTRUMENTATION) \ + +#endif /* GC_INSTRUCTIONS_H_ */ diff --git a/Makefile b/Makefile index 5678d9fa..0d670b03 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt include CONFIG @@ -17,6 +17,8 @@ ifeq ($(USE_NTL),1) FHEOFFLINE = $(patsubst %.cpp,%.o,$(wildcard FHEOffline/*.cpp FHE/*.cpp)) endif +GC = $(patsubst %.cpp,%.o,$(wildcard GC/*.cpp)) + # OT stuff needs GF2N_LONG, so only compile if this is enabled ifeq ($(USE_GF2N_LONG),1) OT = $(patsubst %.cpp,%.o,$(filter-out OT/OText_main.cpp,$(wildcard OT/*.cpp))) @@ -25,12 +27,14 @@ endif COMMON = $(MATH) $(TOOLS) $(NETWORK) $(AUTH) COMPLETE = $(COMMON) $(PROCESSOR) $(FHEOFFLINE) $(TINYOTOFFLINE) $(OT) +BMR = $(patsubst %.cpp,%.o,$(wildcard BMR/*.cpp BMR/network/*.cpp)) $(COMMON) $(PROCESSOR) $(GC) + LIB = libSPDZ.a LIBSIMPLEOT = SimpleOT/libsimpleot.a # used for dependency generation -OBJS = $(COMPLETE) +OBJS = $(BMR) $(FHEOFFLINE) $(TINYOTOFFLINE) DEPS := $(OBJS:.o=.d) @@ -53,6 +57,8 @@ gen_input: gen_input_f2n.x gen_input_fp.x externalIO: client-setup.x bankers-bonus-client.x bankers-bonus-commsec-client.x +bmr: bmr-program-party.x bmr-program-tparty.x + she-offline: Check-Offline.x spdz2-offline.x overdrive: simple-offline.x pairwise-offline.x cnc-offline.x @@ -92,6 +98,18 @@ gen_input_f2n.x: Scripts/gen_input_f2n.cpp $(COMMON) gen_input_fp.x: Scripts/gen_input_fp.cpp $(COMMON) $(CXX) $(CFLAGS) Scripts/gen_input_fp.cpp -o gen_input_fp.x $(COMMON) $(LDLIBS) +gc-emulate.x: $(GC) $(COMMON) $(PROCESSOR) gc-emulate.cpp $(BMR) + $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) $(BOOST) + +bmr-program-party.x: $(BMR) bmr-program-party.cpp + $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) $(BOOST) + +bmr-program-tparty.x: $(BMR) bmr-program-tparty.cpp + $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) $(BOOST) + +bmr-clean: + -rm BMR/*.o BMR/*/*.o GC/*.o + client-setup.x: client-setup.cpp $(COMMON) $(PROCESSOR) $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) @@ -116,4 +134,4 @@ spdz2-offline.x: $(COMMON) $(FHEOFFLINE) spdz2-offline.cpp endif clean: - -rm */*.o *.o */*.d *.d *.x core.* *.a gmon.out + -rm */*.o *.o */*.d *.d *.x core.* *.a gmon.out */*/*.o diff --git a/Math/Integer.cpp b/Math/Integer.cpp index 478c6e63..75d03467 100644 --- a/Math/Integer.cpp +++ b/Math/Integer.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Integer.cpp diff --git a/Math/Integer.h b/Math/Integer.h index 863b605f..f4d7faa3 100644 --- a/Math/Integer.h +++ b/Math/Integer.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Integer.h @@ -26,6 +26,7 @@ protected: Integer(long a) : a(a) {} long get() const { return a; } + bool get_bit(int i) const { return (a >> i) & 1; } void assign_zero() { a = 0; } diff --git a/Math/Setup.cpp b/Math/Setup.cpp index b13ba30c..1c441014 100644 --- a/Math/Setup.cpp +++ b/Math/Setup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/Setup.h" diff --git a/Math/Setup.h b/Math/Setup.h index ca9efa6b..1dac66f4 100644 --- a/Math/Setup.h +++ b/Math/Setup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Setup.h diff --git a/Math/Share.cpp b/Math/Share.cpp index 569a661c..b7373e6e 100644 --- a/Math/Share.cpp +++ b/Math/Share.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Share.h" @@ -8,17 +8,6 @@ #include "Math/operators.h" -template -Share::Share(const T& aa, int my_num, const T& alphai) -{ - if (my_num == 0) - a = aa; - else - a.assign_zero(); - mac = aa * alphai; -} - - template void Share::mul_by_bit(const Share& S,const T& aa) { diff --git a/Math/Share.h b/Math/Share.h index 35a0a369..ee62bf8b 100644 --- a/Math/Share.h +++ b/Math/Share.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Share @@ -43,10 +43,11 @@ class Share { a.assign_zero(); mac.assign_zero(); } + void assign(const T& aa, int my_num, const T& alphai); Share() { assign_zero(); } Share(const Share& S) { assign(S); } - Share(const T& aa, int my_num, const T& alphai); + Share(const T& aa, int my_num, const T& alphai) { assign(aa, my_num, alphai); } ~Share() { ; } Share& operator=(const Share& S) { if (this!=&S) { assign(S); } @@ -132,4 +133,14 @@ inline void Share::mul(const Share& S,const T& aa) mac.mul(S.mac,aa); } +template +inline void Share::assign(const T& aa, int my_num, const T& alphai) +{ + if (my_num == 0) + a = aa; + else + a.assign_zero(); + mac.mul(aa, alphai); +} + #endif diff --git a/Math/Subroutines.cpp b/Math/Subroutines.cpp index 3c2d5515..f7aa31ff 100644 --- a/Math/Subroutines.cpp +++ b/Math/Subroutines.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Subroutines.h" diff --git a/Math/Subroutines.h b/Math/Subroutines.h index d4ea66b7..24458686 100644 --- a/Math/Subroutines.h +++ b/Math/Subroutines.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Subroutines #define _Subroutines diff --git a/Math/Zp_Data.cpp b/Math/Zp_Data.cpp index 65934813..b5381c28 100644 --- a/Math/Zp_Data.cpp +++ b/Math/Zp_Data.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Zp_Data.h" diff --git a/Math/Zp_Data.h b/Math/Zp_Data.h index 4c26b729..70393313 100644 --- a/Math/Zp_Data.h +++ b/Math/Zp_Data.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Zp_Data #define _Zp_Data diff --git a/Math/bigint.cpp b/Math/bigint.cpp index 3d28a738..c973cce0 100644 --- a/Math/bigint.cpp +++ b/Math/bigint.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "bigint.h" diff --git a/Math/bigint.h b/Math/bigint.h index d28adddd..22b209a8 100644 --- a/Math/bigint.h +++ b/Math/bigint.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _bigint #define _bigint diff --git a/Math/field_types.h b/Math/field_types.h index 997cd879..74f116b7 100644 --- a/Math/field_types.h +++ b/Math/field_types.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * types.h diff --git a/Math/gf2n.cpp b/Math/gf2n.cpp index 6f4eb792..0fed448c 100644 --- a/Math/gf2n.cpp +++ b/Math/gf2n.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/gf2n.h" diff --git a/Math/gf2n.h b/Math/gf2n.h index 3ba8e079..16b5f73b 100644 --- a/Math/gf2n.h +++ b/Math/gf2n.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _gf2n #define _gf2n diff --git a/Math/gf2nlong.cpp b/Math/gf2nlong.cpp index 0ee996aa..2e0fe43e 100644 --- a/Math/gf2nlong.cpp +++ b/Math/gf2nlong.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * gf2n_longlong.cpp @@ -30,6 +30,7 @@ ostream& operator<<(ostream& s, const int128& a) { word* tmp = (word*)&a.a; s << hex; + s << noshowbase; s.width(16); s.fill('0'); s << tmp[1]; @@ -160,19 +161,6 @@ void gf2n_long::reduce_pentanomial(int128 xh, int128 xl) } -gf2n_long& gf2n_long::mul(const gf2n_long& x,const gf2n_long& y) -{ - __m128i res[2]; - avx_memzero(res, sizeof(res)); - - mul128(x.a.a,y.a.a,res,res+1); - - reduce(res[1],res[0]); - - return *this; -} - - class int129 { int128 lower; diff --git a/Math/gf2nlong.h b/Math/gf2nlong.h index aa49a837..c5d56cef 100644 --- a/Math/gf2nlong.h +++ b/Math/gf2nlong.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * gf2nlong.h @@ -32,7 +32,8 @@ public: int128(const word& a) : a(_mm_cvtsi64_si128(a)) { } int128(const word& upper, const word& lower) : a(_mm_set_epi64x(upper, lower)) { } - word get_lower() { return (word)_mm_cvtsi128_si64(a); } + word get_lower() const { return (word)_mm_cvtsi128_si64(a); } + word get_upper() const { return _mm_extract_epi64(a, 1); } bool operator==(const int128& other) const { return _mm_test_all_zeros(a ^ other.a, a ^ other.a); } bool operator!=(const int128& other) const { return !(*this == other); } @@ -54,6 +55,9 @@ public: int128& operator&=(const int128& other) { a &= other.a; return *this; } friend ostream& operator<<(ostream& s, const int128& a); + + static int128 ones(int n); + bool get_bit(int i) const; }; @@ -278,4 +282,32 @@ inline void mul128(__m128i a, __m128i b, __m128i *res1, __m128i *res2) *res2 = tmp6; } +inline int128 int128::ones(int n) +{ + if (n < 64) + return int128(0, (1ULL << n) - 1); + else + return int128((1ULL << (n - 64)) - 1, -1); +} + +inline bool int128::get_bit(int i) const +{ + if (i < 64) + return (get_lower() >> i) & 1; + else + return (get_upper() >> (i - 64)) & 1; +} + +inline gf2n_long& gf2n_long::mul(const gf2n_long& x,const gf2n_long& y) +{ + __m128i res[2]; + memset(res,0,sizeof(res)); + + mul128(x.a.a,y.a.a,res,res+1); + + reduce(res[1],res[0]); + + return *this; +} + #endif /* MATH_GF2NLONG_H_ */ diff --git a/Math/gfp.cpp b/Math/gfp.cpp index 2b865b34..fa1ed168 100644 --- a/Math/gfp.cpp +++ b/Math/gfp.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/gfp.h" diff --git a/Math/gfp.h b/Math/gfp.h index 92d2e8ab..e981f358 100644 --- a/Math/gfp.h +++ b/Math/gfp.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _gfp #define _gfp diff --git a/Math/modp.cpp b/Math/modp.cpp index a3840742..ff161ff0 100644 --- a/Math/modp.cpp +++ b/Math/modp.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Zp_Data.h" #include "modp.h" diff --git a/Math/modp.h b/Math/modp.h index 950c133f..f7fa1d02 100644 --- a/Math/modp.h +++ b/Math/modp.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Modp #define _Modp diff --git a/Math/operators.h b/Math/operators.h index 9c5d5835..937c1200 100644 --- a/Math/operators.h +++ b/Math/operators.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * operations.h diff --git a/Networking/Player.cpp b/Networking/Player.cpp index 343f1bfe..bb0259c8 100644 --- a/Networking/Player.cpp +++ b/Networking/Player.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Player.h" @@ -182,6 +182,11 @@ Player::~Player() /* Close down the sockets */ for (int i=0; ifirst << " " << 1e-6 * it->second.data << " MB in " + << it->second.rounds << " rounds, taking " << it->second.timer.elapsed() + << " seconds" << endl; } @@ -226,8 +231,8 @@ void Player::setup_sockets(const vector& names,const vector& ports, void Player::send_to(int player,const octetStream& o,bool donthash) const -{ - TimeScope ts(timer); +{ + TimeScope ts(comm_stats["Sending directly"].add(o)); int socket = socket_to_send(player); o.Send(socket); if (!donthash) @@ -238,7 +243,7 @@ void Player::send_to(int player,const octetStream& o,bool donthash) const void Player::send_all(const octetStream& o,bool donthash) const { - TimeScope ts(timer); + TimeScope ts(comm_stats["Sending to all"].add(o)); for (int i=0; i& o,bool donthash) const { - TimeScope ts(timer); - for (int i=0; iplayer_no) - { o[player_no].Send(sockets[i]); } - else if (iplayer_no) - { o[i].reset_write_head(); - o[i].Receive(sockets[i]); - } - } + if (o.size() != sockets.size()) + throw runtime_error("player numbers don't match"); + TimeScope ts(comm_stats["Broadcasting"].add(o[player_no])); + for (int i=1; i comm_stats; + public: // The offset is used for the multi-threaded call, to ensure different // portnum bases in each thread diff --git a/Networking/Receiver.cpp b/Networking/Receiver.cpp index 893ecca5..843d2150 100644 --- a/Networking/Receiver.cpp +++ b/Networking/Receiver.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Receiver.cpp diff --git a/Networking/Receiver.h b/Networking/Receiver.h index cd24a009..df6989e2 100644 --- a/Networking/Receiver.h +++ b/Networking/Receiver.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Receiver.h diff --git a/Networking/STS.cpp b/Networking/STS.cpp index b634b448..6efb28e3 100644 --- a/Networking/STS.cpp +++ b/Networking/STS.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Networking/STS.h" #include diff --git a/Networking/STS.h b/Networking/STS.h index 8749c743..66ff65d3 100644 --- a/Networking/STS.h +++ b/Networking/STS.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _NETWORK_STS #define _NETWORK_STS diff --git a/Networking/Sender.cpp b/Networking/Sender.cpp index 1fda64f6..31e7cc07 100644 --- a/Networking/Sender.cpp +++ b/Networking/Sender.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Sender.cpp diff --git a/Networking/Sender.h b/Networking/Sender.h index 205fed9e..1193241c 100644 --- a/Networking/Sender.h +++ b/Networking/Sender.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Sender.h diff --git a/Networking/Server.cpp b/Networking/Server.cpp index 412b0cbf..47851277 100644 --- a/Networking/Server.cpp +++ b/Networking/Server.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Networking/sockets.h" diff --git a/Networking/Server.h b/Networking/Server.h index 447accd0..b9cd0a3b 100644 --- a/Networking/Server.h +++ b/Networking/Server.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Server.h diff --git a/Networking/ServerSocket.cpp b/Networking/ServerSocket.cpp index 8bd8db83..04046ec9 100644 --- a/Networking/ServerSocket.cpp +++ b/Networking/ServerSocket.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * ServerSocket.cpp diff --git a/Networking/ServerSocket.h b/Networking/ServerSocket.h index dedc2f6c..81e0ad68 100644 --- a/Networking/ServerSocket.h +++ b/Networking/ServerSocket.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * ServerSocket.h diff --git a/Networking/data.h b/Networking/data.h index 2650d755..a4c63771 100644 --- a/Networking/data.h +++ b/Networking/data.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Data #define _Data @@ -27,8 +27,13 @@ inline void encode_length(octet *buff, size_t len, size_t n_bytes) { if (n_bytes > 8) throw invalid_length("length field cannot be more than 64 bits"); - if (n_bytes < 8 && (len > (1ULL << (8 * n_bytes)))) - throw invalid_length("length too large for length field"); + if (n_bytes < 8) + { + long long upper = len; + upper >>= (8 * n_bytes); + if (upper != 0 and upper != -1) + throw invalid_length("length too large for length field"); + } for (size_t i = 0; i < n_bytes; i++) buff[i] = len >> (8 * i); } diff --git a/Networking/sockets.cpp b/Networking/sockets.cpp index e9fc1dc9..7169449d 100644 --- a/Networking/sockets.cpp +++ b/Networking/sockets.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "sockets.h" diff --git a/Networking/sockets.h b/Networking/sockets.h index 739cffb1..d5d49724 100644 --- a/Networking/sockets.h +++ b/Networking/sockets.h @@ -1,7 +1,7 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt -#ifndef _sockets -#define _sockets +#ifndef _sockets_h +#define _sockets_h #include "Networking/data.h" @@ -90,4 +90,35 @@ inline void receive(int socket,octet *msg,size_t len) } } +inline size_t check_non_blocking_result(int res) +{ + if (res < 0) + { + if (errno != EWOULDBLOCK) + error("Non-blocking receiving error"); + return 0; + } + return res; +} + +inline size_t receive_non_blocking(int socket,octet *msg,int len) +{ + int res = recv(socket, msg, len, MSG_DONTWAIT); + return check_non_blocking_result(res); +} + +inline size_t receive_all_or_nothing(int socket,octet *msg,int len) +{ + int res = recv(socket, msg, len, MSG_DONTWAIT | MSG_PEEK); + check_non_blocking_result(res); + if (res == len) + { + if (recv(socket, msg, len, 0) != len) + error("All or nothing receiving error"); + return len; + } + else + return 0; +} + #endif diff --git a/OT/BaseOT.cpp b/OT/BaseOT.cpp index d0fcd811..e1789480 100644 --- a/OT/BaseOT.cpp +++ b/OT/BaseOT.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "OT/BaseOT.h" #include "Tools/random.h" diff --git a/OT/BaseOT.h b/OT/BaseOT.h index 2919814f..71c37678 100644 --- a/OT/BaseOT.h +++ b/OT/BaseOT.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _BASE_OT #define _BASE_OT diff --git a/OT/BitMatrix.cpp b/OT/BitMatrix.cpp index e07942b9..c02820ee 100644 --- a/OT/BitMatrix.cpp +++ b/OT/BitMatrix.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * BitMatrix.cpp diff --git a/OT/BitMatrix.h b/OT/BitMatrix.h index 7dbb3fcd..e0226481 100644 --- a/OT/BitMatrix.h +++ b/OT/BitMatrix.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * BitMatrix.h diff --git a/OT/BitVector.cpp b/OT/BitVector.cpp index c560ff87..01b7773a 100644 --- a/OT/BitVector.cpp +++ b/OT/BitVector.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "OT/BitVector.h" diff --git a/OT/BitVector.h b/OT/BitVector.h index 02798519..472a208d 100644 --- a/OT/BitVector.h +++ b/OT/BitVector.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _BITVECTOR #define _BITVECTOR diff --git a/OT/NPartyTripleGenerator.cpp b/OT/NPartyTripleGenerator.cpp index f1ef2c82..b7e88653 100644 --- a/OT/NPartyTripleGenerator.cpp +++ b/OT/NPartyTripleGenerator.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "NPartyTripleGenerator.h" diff --git a/OT/NPartyTripleGenerator.h b/OT/NPartyTripleGenerator.h index 0003c8ae..4119c465 100644 --- a/OT/NPartyTripleGenerator.h +++ b/OT/NPartyTripleGenerator.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef OT_NPARTYTRIPLEGENERATOR_H_ #define OT_NPARTYTRIPLEGENERATOR_H_ diff --git a/OT/OTExtension.cpp b/OT/OTExtension.cpp index 264d72a8..a29f6226 100644 --- a/OT/OTExtension.cpp +++ b/OT/OTExtension.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "OTExtension.h" diff --git a/OT/OTExtension.h b/OT/OTExtension.h index a3b3f32e..f5e9e09d 100644 --- a/OT/OTExtension.h +++ b/OT/OTExtension.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _OTEXTENSION #define _OTEXTENSION diff --git a/OT/OTExtensionWithMatrix.cpp b/OT/OTExtensionWithMatrix.cpp index 12c3f57b..f0d980ba 100644 --- a/OT/OTExtensionWithMatrix.cpp +++ b/OT/OTExtensionWithMatrix.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OTExtensionWithMatrix.cpp diff --git a/OT/OTExtensionWithMatrix.h b/OT/OTExtensionWithMatrix.h index 08a51f87..64b101e6 100644 --- a/OT/OTExtensionWithMatrix.h +++ b/OT/OTExtensionWithMatrix.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OTExtensionWithMatrix.h diff --git a/OT/OTMachine.cpp b/OT/OTMachine.cpp index dbd8120d..8ab4115d 100644 --- a/OT/OTMachine.cpp +++ b/OT/OTMachine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Networking/Player.h" #include "OT/OTExtension.h" diff --git a/OT/OTMachine.h b/OT/OTMachine.h index 8b234826..8c75ea19 100644 --- a/OT/OTMachine.h +++ b/OT/OTMachine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OTMachine.h diff --git a/OT/OTMultiplier.cpp b/OT/OTMultiplier.cpp index 00928956..5399f7a7 100644 --- a/OT/OTMultiplier.cpp +++ b/OT/OTMultiplier.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OTMultiplier.cpp diff --git a/OT/OTMultiplier.h b/OT/OTMultiplier.h index cf52d445..ba55f75d 100644 --- a/OT/OTMultiplier.h +++ b/OT/OTMultiplier.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OTMultiplier.h diff --git a/OT/OTTripleSetup.cpp b/OT/OTTripleSetup.cpp index 994c9f32..bbba4d99 100644 --- a/OT/OTTripleSetup.cpp +++ b/OT/OTTripleSetup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "OTTripleSetup.h" diff --git a/OT/OTTripleSetup.h b/OT/OTTripleSetup.h index 93eaae7d..946cfcf4 100644 --- a/OT/OTTripleSetup.h +++ b/OT/OTTripleSetup.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef OT_TRIPLESETUP_H_ #define OT_TRIPLESETUP_H_ diff --git a/OT/OText_main.cpp b/OT/OText_main.cpp index b2a32286..60f7c3c3 100644 --- a/OT/OText_main.cpp +++ b/OT/OText_main.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OText_main.cpp diff --git a/OT/OutputCheck.h b/OT/OutputCheck.h index de97b926..2a5a1e58 100644 --- a/OT/OutputCheck.h +++ b/OT/OutputCheck.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * check.h diff --git a/OT/Tools.cpp b/OT/Tools.cpp index c351de76..4448e811 100644 --- a/OT/Tools.cpp +++ b/OT/Tools.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Tools.h" #include "Math/gf2nlong.h" diff --git a/OT/Tools.h b/OT/Tools.h index c743305b..4d64f9c3 100644 --- a/OT/Tools.h +++ b/OT/Tools.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _OTTOOLS #define _OTTOOLS diff --git a/OT/TripleMachine.cpp b/OT/TripleMachine.cpp index e6440ac5..b46af776 100644 --- a/OT/TripleMachine.cpp +++ b/OT/TripleMachine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * TripleMachine.cpp diff --git a/OT/TripleMachine.h b/OT/TripleMachine.h index 07cbb126..f1e85d26 100644 --- a/OT/TripleMachine.h +++ b/OT/TripleMachine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * TripleMachine.h diff --git a/Player-Online.cpp b/Player-Online.cpp index d4ed7645..0e843ea2 100644 --- a/Player-Online.cpp +++ b/Player-Online.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Machine.h" #include "Math/Setup.h" diff --git a/Processor/Binary_File_IO.cpp b/Processor/Binary_File_IO.cpp index 090abe2a..ea6c2ecb 100644 --- a/Processor/Binary_File_IO.cpp +++ b/Processor/Binary_File_IO.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Binary_File_IO.h" #include "Math/gfp.h" diff --git a/Processor/Binary_File_IO.h b/Processor/Binary_File_IO.h index a9b38a58..1504aec7 100644 --- a/Processor/Binary_File_IO.h +++ b/Processor/Binary_File_IO.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _FILE_IO_HEADER #define _FILE_IO_HEADER diff --git a/Processor/Buffer.cpp b/Processor/Buffer.cpp index cbb313bd..82bce5f5 100644 --- a/Processor/Buffer.cpp +++ b/Processor/Buffer.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Buffer.cpp diff --git a/Processor/Buffer.h b/Processor/Buffer.h index c519588c..aa8cc59f 100644 --- a/Processor/Buffer.h +++ b/Processor/Buffer.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Buffer.h diff --git a/Processor/Data_Files.cpp b/Processor/Data_Files.cpp index 6618ac1c..9ea81342 100644 --- a/Processor/Data_Files.cpp +++ b/Processor/Data_Files.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Data_Files.h" diff --git a/Processor/Data_Files.h b/Processor/Data_Files.h index 86637cf6..ccf8189a 100644 --- a/Processor/Data_Files.h +++ b/Processor/Data_Files.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Data_Files #define _Data_Files diff --git a/Processor/ExternalClients.cpp b/Processor/ExternalClients.cpp index 57d18ff9..0cb90164 100644 --- a/Processor/ExternalClients.cpp +++ b/Processor/ExternalClients.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/ExternalClients.h" #include diff --git a/Processor/ExternalClients.h b/Processor/ExternalClients.h index 68b0594a..cc7f69e1 100644 --- a/Processor/ExternalClients.h +++ b/Processor/ExternalClients.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _ExternalClients #define _ExternalClients diff --git a/Processor/Input.cpp b/Processor/Input.cpp index 640f8a0d..dcb1bffd 100644 --- a/Processor/Input.cpp +++ b/Processor/Input.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Input.cpp diff --git a/Processor/Input.h b/Processor/Input.h index 0f54ec08..1655cced 100644 --- a/Processor/Input.h +++ b/Processor/Input.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Input.h diff --git a/Processor/InputTuple.h b/Processor/InputTuple.h index 9a78848c..2d8459d1 100644 --- a/Processor/InputTuple.h +++ b/Processor/InputTuple.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * InputTuple.h diff --git a/Processor/Instruction.cpp b/Processor/Instruction.cpp index ff7cd934..fd24e50d 100644 --- a/Processor/Instruction.cpp +++ b/Processor/Instruction.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Instruction.h" @@ -12,7 +12,10 @@ #include #include #include +#include +// broken +#undef DEBUG // Convert modp to signed bigint of a given bit length void to_signed_bigint(bigint& bi, const gfp& x, int len) @@ -256,6 +259,8 @@ void BaseInstruction::parse_operands(istream& s, int pos) // instructions with no operand case TIME: case CRASH: + case STARTGRIND: + case STOPGRIND: break; // instructions with 4 register operands case PRINTFLOATPLAIN: @@ -321,6 +326,11 @@ void BaseInstruction::parse_operands(istream& s, int pos) n = get_int(s); get_vector(num_var_args, start, s); break; + case BITDECINT: + num_var_args = get_int(s) - 1; + r[0] = get_int(s); + get_vector(num_var_args, start, s); + break; case PREP: case GPREP: // subtract extra argument @@ -1346,6 +1356,15 @@ void Instruction::execute(Processor& Proc) const Proc.get_C2_ref(r[0] + j) = a; } return; + case BITDECINT: + { + long a = Proc.read_Ci(r[0]); + for (unsigned int i = 0; i < start.size(); i++) + { + Proc.get_Ci_ref(start[i]) = (a >> i) & 1; + } + break; + } case STARTOPEN: Proc.POpen_Start(start,Proc.P,Proc.MCp,size); return; @@ -1547,6 +1566,12 @@ void Instruction::execute(Processor& Proc) const case CRASH: throw crash_requested(); break; + case STARTGRIND: + CALLGRIND_START_INSTRUMENTATION; + break; + case STOPGRIND: + CALLGRIND_STOP_INSTRUMENTATION; + break; // *** // TODO: read/write shared GF(2^n) data instructions // *** diff --git a/Processor/Instruction.h b/Processor/Instruction.h index e674c33b..2d095a48 100644 --- a/Processor/Instruction.h +++ b/Processor/Instruction.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Instruction #define _Instruction @@ -64,6 +64,8 @@ enum JOIN_TAPE = 0x1A, CRASH = 0x1B, USE_PREP = 0x1C, + STARTGRIND = 0x1D, + STOPGRIND = 0x1E, // Addition ADDC = 0x20, ADDS = 0x21, @@ -138,6 +140,7 @@ enum EQC = 0x97, JMPI = 0x98, // Integers + BITDECINT = 0x99, LDINT = 0x9A, ADDINT = 0x9B, SUBINT = 0x9C, diff --git a/Processor/Machine.cpp b/Processor/Machine.cpp index 22742da9..9582b9aa 100644 --- a/Processor/Machine.cpp +++ b/Processor/Machine.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Machine.h" diff --git a/Processor/Machine.h b/Processor/Machine.h index eb3e13dc..cd25fc80 100644 --- a/Processor/Machine.h +++ b/Processor/Machine.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Machine.h diff --git a/Processor/Memory.cpp b/Processor/Memory.cpp index 4cc2d729..d1510804 100644 --- a/Processor/Memory.cpp +++ b/Processor/Memory.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Memory.h" #include "Processor/Instruction.h" diff --git a/Processor/Memory.h b/Processor/Memory.h index cad6798d..f0ffe40f 100644 --- a/Processor/Memory.h +++ b/Processor/Memory.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Memory #define _Memory diff --git a/Processor/Online-Thread.cpp b/Processor/Online-Thread.cpp index 40e6b544..2c0b1542 100644 --- a/Processor/Online-Thread.cpp +++ b/Processor/Online-Thread.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Program.h" diff --git a/Processor/Online-Thread.h b/Processor/Online-Thread.h index 759c5e8e..7c462552 100644 --- a/Processor/Online-Thread.h +++ b/Processor/Online-Thread.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Online_Thread #define _Online_Thread diff --git a/Processor/PrivateOutput.cpp b/Processor/PrivateOutput.cpp index 3b59cc6b..1ccb5e4b 100644 --- a/Processor/PrivateOutput.cpp +++ b/Processor/PrivateOutput.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PrivateOutput.cpp diff --git a/Processor/PrivateOutput.h b/Processor/PrivateOutput.h index c73dfc58..f4cc4ef7 100644 --- a/Processor/PrivateOutput.h +++ b/Processor/PrivateOutput.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * PrivateOutput.h diff --git a/Processor/Processor.cpp b/Processor/Processor.cpp index 8ce13488..ac01f1fd 100644 --- a/Processor/Processor.cpp +++ b/Processor/Processor.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Processor.h" diff --git a/Processor/Processor.h b/Processor/Processor.h index 5e7808e6..2dfae97b 100644 --- a/Processor/Processor.h +++ b/Processor/Processor.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Processor diff --git a/Processor/Program.cpp b/Processor/Program.cpp index e0f8c859..28caccde 100644 --- a/Processor/Program.cpp +++ b/Processor/Program.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Program.h" diff --git a/Processor/Program.h b/Processor/Program.h index 63a66bdb..94763879 100644 --- a/Processor/Program.h +++ b/Processor/Program.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Program #define _Program diff --git a/Programs/Source/aes.mpc b/Programs/Source/aes.mpc index 151e1160..a6eff53a 100644 --- a/Programs/Source/aes.mpc +++ b/Programs/Source/aes.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from copy import copy diff --git a/Programs/Source/bankers_bonus.mpc b/Programs/Source/bankers_bonus.mpc index 3a187fef..5954b0b1 100644 --- a/Programs/Source/bankers_bonus.mpc +++ b/Programs/Source/bankers_bonus.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt # coding: latin-1 """ Solve Bankers bonus, aka Millionaires problem. diff --git a/Programs/Source/bankers_bonus_commsec.mpc b/Programs/Source/bankers_bonus_commsec.mpc index ccb17e66..e3559b03 100644 --- a/Programs/Source/bankers_bonus_commsec.mpc +++ b/Programs/Source/bankers_bonus_commsec.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt # coding: latin-1 """ Solve Bankers bonus, aka Millionaires problem. diff --git a/Programs/Source/dijkstra_tutorial.mpc b/Programs/Source/dijkstra_tutorial.mpc index 993b6da5..f81d6801 100644 --- a/Programs/Source/dijkstra_tutorial.mpc +++ b/Programs/Source/dijkstra_tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import dijkstra from path_oram import OptimalORAM diff --git a/Programs/Source/fixed_point_tutorial.mpc b/Programs/Source/fixed_point_tutorial.mpc index 00c13e36..fd4c2f8c 100644 --- a/Programs/Source/fixed_point_tutorial.mpc +++ b/Programs/Source/fixed_point_tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt program.bit_length = 80 print "program.bit_length: ", program.bit_length diff --git a/Programs/Source/gale-shapley_tutorial.mpc b/Programs/Source/gale-shapley_tutorial.mpc index 2455e878..54122b28 100644 --- a/Programs/Source/gale-shapley_tutorial.mpc +++ b/Programs/Source/gale-shapley_tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler import gs from Compiler.path_oram import OptimalORAM diff --git a/Programs/Source/gc_oram.mpc b/Programs/Source/gc_oram.mpc new file mode 100644 index 00000000..a8f159ee --- /dev/null +++ b/Programs/Source/gc_oram.mpc @@ -0,0 +1,31 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +prog = program + +from Compiler.GC.types import * +from Compiler.GC.instructions import * + +program.to_merge = [ldmsdi, stmsdi, ldmsd, stmsd, stmsdci, xors, andrs] +program.stop_class = type(None) + +from Compiler.circuit_oram import * +from Compiler import circuit_oram + +from Compiler import oram +oram.n_threads = 1 +oram.n_threads_for_tree = 1 + +# ORAM/array size +n = 1000000 + +# some parameters +oram.max_demux_bits = 0 +circuit_oram.threshold = 128 + +# Circuit ORAM +oram_type = AtLeastOneRecursionPackedCircuitORAM + +# linear scan (no ORAM) +#oram_type = LinearORAM + +oram = test_oram(oram_type, n, value_type=sbits, iterations=3) diff --git a/Programs/Source/htmac.mpc b/Programs/Source/htmac.mpc index 928fdf5c..22ef224f 100644 --- a/Programs/Source/htmac.mpc +++ b/Programs/Source/htmac.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt """ Execfile can be avoided by implementing this ORAM-style (put .py sources in Compiler/ directory) diff --git a/Programs/Source/oram_tutorial.mpc b/Programs/Source/oram_tutorial.mpc index 23fa58fa..c3b7fbfa 100644 --- a/Programs/Source/oram_tutorial.mpc +++ b/Programs/Source/oram_tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from path_oram import OptimalORAM diff --git a/Programs/Source/prf_leg.mpc b/Programs/Source/prf_leg.mpc index afe914c0..f50695ba 100644 --- a/Programs/Source/prf_leg.mpc +++ b/Programs/Source/prf_leg.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler import instructions_base import sys diff --git a/Programs/Source/prf_mimc.mpc b/Programs/Source/prf_mimc.mpc index 24f812d5..f97a6146 100644 --- a/Programs/Source/prf_mimc.mpc +++ b/Programs/Source/prf_mimc.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt from Compiler import instructions_base import sys diff --git a/Programs/Source/test_gc.mpc b/Programs/Source/test_gc.mpc new file mode 100644 index 00000000..73160ca2 --- /dev/null +++ b/Programs/Source/test_gc.mpc @@ -0,0 +1,69 @@ +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +program.options.merge_opens = False + +from Compiler.GC.types import sbits, sbit, cbits + +def test(a, b, value_type=None): + try: + a = a.reveal() + except AttributeError: + pass + import inspect + print_ln('%s: %s %s %s', inspect.currentframe().f_back.f_lineno, \ + (a ^ cbits(b)).reveal(), a, hex(b)) + +test(sbits(3) + sbits(5), 3 ^ 5) +test(cbits(3) + cbits(5), 3 + 5) +test(cbits(3) + (5), 3 + 5) +test(cbits(3) ^ cbits(5), 3 ^ 5) +test(cbits(3) ^ (5), 3 ^ 5) +test(sbits(3) + 5, 3 ^ 5) +test(sbits(3) - sbits(5), 3 ^ 5) +test(sbit(1) * sbits(3), 3) +#test(cbits(1) * cbits(3), 3) +test(sbit(1) * 3, 3) +test(~sbits(1, n=64), 2**64 - 2) +test(sbits(3).equal(sbits(3)), 1) +test(sbits(3).equal(sbits(2)), 0) +test(sbit(1).if_else(sbits(3), sbits(5)), 3) +test(sbits(7) << 1, 14) +test(cbits(5) >> 1, 2) +test(sbit.bit_compose((sbit(1), sbit(0), sbit(1))), 5) +test(sbit(0).if_else(1, 2), 2) +test(sbit(1).if_else(1, 2), 1) +test(sbit(0).if_else(2, 1), 1) +test(sbit(1).if_else(2, 1), 2) + +test(sbits.compose((sbits(2), sbits(1, n=2)), 2), 6) + +x = MemValue(sbits(1234)) +program.curr_tape.start_new_basicblock() +test(x, 1234) + +x = MemValue(cbits(123)) +program.curr_tape.start_new_basicblock() +test(x, 123) + +x = memorize(cbits(234)) +program.curr_tape.start_new_basicblock() +test(unmemorize(x), 234) + +cbits(456).store_in_mem(1234) +program.curr_tape.start_new_basicblock() +test(cbits.load_mem(1234), 456) + +test(sbits(1 << 63, n=64), 1 << 63) + +bits = sbits(0x1234, n=40).bit_decompose(40) +test(sbits.bit_compose(bits), 0x1234) + +test(sbits(5, n=4) ^ sbits(3, n=3), 6) +test(sbits(5, n=3) ^ sbits(3, n=4), 6) +test(sbits(13, n=4) ^ sbits(3, n=3), 14) +test(sbits(5, n=3) ^ sbits(11, n=4), 14) + +b = sbits.get_random_bit() +test(b * (1 - b), 0) +bits = [sbits.get_random_bit() for i in range(40)] +print_ln('random: %s', sbits.bit_compose(bits).reveal()) diff --git a/Programs/Source/tpmpc_tutorial.mpc b/Programs/Source/tpmpc_tutorial.mpc index 0f3ac92d..ac3fd718 100644 --- a/Programs/Source/tpmpc_tutorial.mpc +++ b/Programs/Source/tpmpc_tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt """ Example programs used in the SPDZ tutorial at the TPMPC 2017 workshop in Bristol. diff --git a/Programs/Source/tutorial.mpc b/Programs/Source/tutorial.mpc index 7283c496..ca870600 100644 --- a/Programs/Source/tutorial.mpc +++ b/Programs/Source/tutorial.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt def test(actual, expected): if isinstance(actual, (sint, sgf2n)): diff --git a/Programs/Source/vickrey.mpc b/Programs/Source/vickrey.mpc index be691d13..3f269eb9 100644 --- a/Programs/Source/vickrey.mpc +++ b/Programs/Source/vickrey.mpc @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt import util from Compiler import types diff --git a/README.md b/README.md index 5eb34ab8..e569123d 100644 --- a/README.md +++ b/README.md @@ -1,166 +1,36 @@ -(C) 2018 University of Bristol. See License.txt +(C) 2018 University of Bristol, Bar-Ilan University. See License.txt -Software for the SPDZ, MASCOT, and Overdrive secure multi-party computation protocols. -See `Programs/Source/` for some example MPC programs, and `tutorial.md` for -a basic tutorial. - -See also https://www.cs.bris.ac.uk/Research/CryptographySecurity/SPDZ +This repository contains the code to benchmark ORAM in SPDZ-BMR as used for the [Eurocrypt 2018 paper](https://eprint.iacr.org/2017/981) by Marcel Keller and Avishay Yanay. #### Preface: -The software contains some functionality for benchmarking that breaks security. This is deactivated by default. See the compilation section on how to activate it if needed. - -In particular, the online phase will discard preprocessed data and crash when it runs out if not in benchmarking mode. In benchmarking mode, it will reuse preprocessed data. +This implementation only allows to benchmark the data-dependent phase. The data-independent and function-independent phases are emulated insecurely. The software should be considered an academic prototype, and we will only give advice on rurunning the examples below. #### Requirements: - GCC (tested with 7.2) or LLVM (tested with 3.8) - MPIR library, compiled with C++ support (use flag --enable-cxx when running configure) - libsodium library, tested against 1.0.11 - CPU supporting AES-NI and PCLMUL - - Python 2.x, ideally with `gmpy` package (for testing) - - NTL library for the SPDZ-2 and Overdrive offline phases (optional; tested with NTL 9.10) + - Python 2.x - If using macOS, Sierra or later -#### To compile SPDZ: +#### To compile: -1) Edit `CONFIG` or `CONFIG.mine` to your needs: +1) Edit `CONFIG` or `CONFIG.mine`: - - To benchmark only the online phase (skipping the secure offline phase), add the following line at the top: `MY_CFLAGS = -DINSECURE` - - `PREP_DIR` should point to should be a local, unversioned directory to store preprocessing data (default is `Player-Data` in the current directory). - - For the SPDZ-2 and Overdrive offline phases, set `USE_NTL = 1` and `MOD = -DMAX_MOD_SZ=6`. - - For the MASCOT offline phase or to use GF(2^128) in the online phase, set `USE_GF2N_LONG = 1`. + - Add the following line at the top: `MY_CFLAGS = -DINSECURE` - For processors without AVX (e.g., Intel Atom) or for optimization, set `ARCH = -march=`. -2) Run make (use the flag -j for faster compilation multiple threads). Remember to run `make clean` first after changing `CONFIG` or `CONFIG.mine`. +2) Run `make bmr` (use the flag -j for faster compilation multiple threads). Remember to run `make clean` first after changing `CONFIG` or `CONFIG.mine`. -#### To setup for benchmarking the online phase +#### Configure the parameters: -This requires the INSECURE flag to be set before compilation as explained above. For a secure offline phase, see the section on SPDZ-2 below. +1) Edit `Program/Source/gc_oram.mpc` to change size and to choose Circuit ORAM or linear scan without ORAM. +2) Run `./compile.py -D gc_oram`. -Run: +#### Run the protocol: -`Scripts/setup-online.sh` +- Run everything locally: `Scripts/bmr-program-run.sh gc_oram`. +- Run on different hosts: `Scripts/bmr-program-run-remote.sh gc_oram [...]` -This sets up parameters for the online phase for 2 parties with a 128-bit prime field and 40-bit binary field, and creates fake offline data (multiplication triples etc.) for these parameters. - -Parameters can be customised by running - -`Scripts/setup-online.sh ` - - -#### To compile a program - -To compile the program in `./Programs/Source/tutorial.mpc`, run: - -`./compile.py tutorial` - -This creates the bytecode and schedule files in Programs/Bytecode/ and Programs/Schedules/ - -#### To run a program - -To run the above program (on one machine), first run: - -`./Server.x 2 5000 &` - -(or replace `5000` with your desired port number) - -Then run both parties' online phase: - -`./Player-Online.x -pn 5000 0 tutorial` - -`./Player-Online.x -pn 5000 1 tutorial` (in a separate terminal) - -Or, you can use a script to do the above automatically: - -`Scripts/run-online.sh tutorial` - -To run a program on two different machines, firstly the preprocessing data must be -copied across to the second machine (or shared using sshfs), and secondly, Player-Online.x -needs to be passed the machine where Server.x is running. -e.g. if this machine is name `diffie` on the local network: - -`./Player-Online.x -pn 5000 -h diffie 0 test_all` - -`./Player-Online.x -pn 5000 -h diffie 1 test_all` - -#### Compiling and running programs from external directories - -Programs can also be edited, compiled and run from any directory with the above basic structure. So for a source file in `./Programs/Source/`, all SPDZ scripts must be run from `./`. The `setup-online.sh` script must also be run from `./` to create the relevant data. For example: - -``` -spdz$ cd ../ -$ mkdir myprogs -$ cd myprogs -$ mkdir -p Programs/Source -$ vi Programs/Source/test.mpc -$ ../spdz/compile.py test.mpc -$ ls Programs/ -Bytecode Public-Input Schedules Source -$ ../spdz/Scripts/setup-online.sh -$ ls -Player-Data Programs -$ ../spdz/Scripts/run-online.sh test -``` - -#### SPDZ-2 offline phase - -This implementation is suitable to generate the preprocessed data used in the online phase. - -For quick run on one machine, you can call the following: - -`./spdz2-offline.x -p 0 & ./spdz2-offline.x -p 1` - -More generally, run the following on every machine: - -`./spdz2-offline.x -p -N -h -c ` - -The number of parties are counted from 0. As seen in the quick example, you can omit the total number of parties if it is 2 and the hostname if all parties run on the same machine. Invoke `./spdz2-offline.x` for more explanation on the options. - -`./spdz2-offline.x` provides covert security according to some parameter c (at least 2). A malicious adversary will get caught with probability 1-1/c. There is a linear correlation between c and the running time, that is, running with 2c takes twice as long as running with c. The default for c is 10. - -The program will generate every kind of randomness required by the online phase until you stop it. You can shut it down gracefully pressing Ctrl-c (or sending the interrupt signal `SIGINT`), but only after an initial phase, the end of which is marked by the output `Starting to produce gf2n`. Note that the initial phase has been reported to take up to an hour. Furthermore, 3 GB of RAM are required per party. - -#### Benchmarking the MASCOT offline phase - -The MASCOT implementation is not suitable to generate the preprocessed data for the online phase because it can only generate either multiplication triples or bits. Nevertheless, an online computation only using data of one kind can run from the output of MASCOT offline phase if `Player-Online.x` is run with the options `-lg2 128 -lgp 128`. - -In order to compile the MASCOT code, the following must be set in CONFIG or CONFIG.mine: - -`USE_GF2N_LONG = 1` - -It also requires SimpleOT: -``` -git submodule update --init SimpleOT -cd SimpleOT -make -``` - -If SPDZ has been built before, any compiled code needs to be removed: - -`make clean` - -HOSTS must contain the hostnames or IPs of the players, see HOSTS.example for an example. - -Then, MASCOT can be run as follows: - -`host1:$ ./ot-offline.x -p 0 -c` - -`host2:$ ./ot-offline.x -p 1 -c` - -#### Benchmarking Overdrive offline phases - -We have implemented several protocols to measure the maximal throughput for the [Overdrive paper](https://eprint.iacr.org/2017/1230). As for MASCOT, these implementations are not suited to generate data for the online phase because they only generate one type at a time. - -Binary | Protocol ------- | -------- -`simple-offline.x` | SPDZ-1 and High Gear (with command-line argument `-g`) -`pairwise-offline.x` | Low Gear -`cnc-offline.x` | SPDZ-2 with malicious security (covert security with command-line argument `-c`) - -These programs can be run similarly to `spdz2-offline.x`, for example: - -`host1:$ ./simple-offline.x -p 0 -h host1` - -`host2:$ ./simple-offline.x -p 1 -h host1` - -Running any program without arguments describes all command-line arguments. +To run with more than two parties, change `CFLAGS = -DN_PARTIES=` in `CONFIG`, and compile again after `make clean`. diff --git a/Scripts/bmr-program-run-remote.sh b/Scripts/bmr-program-run-remote.sh new file mode 100755 index 00000000..1acadaeb --- /dev/null +++ b/Scripts/bmr-program-run-remote.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +while getopts t: opt; do + case $opt in + t) threshold=$OPTARG ;; + esac +done + +shift $[OPTIND-1] + +prog=$1 +shift + +get_ip() +{ + host $1 | grep address | cut -f 4 -d ' ' +} + +port_base=10000 +netmap=netmap.$(hostname) + +add_to_netmap() +{ + port=$[port_base+$2] + if [[ $1 =~ ^[0-9].* ]]; then + echo $1 $port >> $netmap + else + echo $(get_ip $1) $port >> $netmap + fi +} + +i=0 + +echo $[$#+1] > $netmap +add_to_netmap $(hostname) 0 + +for host in $@; do + i=$[i+1] + add_to_netmap $host $i +done + +for host in $@; do + ssh $host killall -9 bmr-party.x bmr-tparty.x memcheck-amd64-valgrind callgrind-amd64-valgrind bmr-program-party.x bmr-program-tparty.x gdb +done + +killall -9 bmr-party.x bmr-tparty.x memcheck-amd64-valgrind callgrind-amd64-valgrind bmr-program-party.x bmr-program-tparty.x + +i=0 +for host in $@; do + i=$[i+1] + #rsync $netmap "$host:$(pwd)" + pwd=$pwd + if test "$prefix" = gdb_screen; then + screen -S :$i -d -m ssh $host "ulimit -c 0; ulimit -v $(grep MemTotal /proc/meminfo | awk '{print $2}'); cd $(pwd); pwd; gdb ./bmr-program-party.x -ex \"run $i $prog $netmap $threshold\"; sleep 100" + else + ssh $host "ulimit -c 0; ulimit -v $(grep MemTotal /proc/meminfo | awk '{print $2}'); cd $(pwd); pwd; { /usr/sbin/tc qdisc; $prefix ./bmr-program-party.x $i $prog $netmap $threshold; } 2>&1 | tee -a logs/bmr-$prog-t$threshold-N$#-$i-$host" & true + fi +done + +ulimit -c 0 +ulimit -v $(grep MemTotal /proc/meminfo | awk '{printf "%d", $2/2}') + +if test "$prefix" = gdb_screen; then + screen -S :t -d -m bash -l -c "cd $(pwd); gdb ./bmr-program-tparty.x -ex \"run $prog $netmap\"; sleep 100" +else + tlog=logs/bmr-$prog-t + { echo netmap trusted; cat $netmap; ./bmr-program-tparty.x $prog $netmap; } 2>&1 | tee $tlog +fi diff --git a/Scripts/bmr-program-run.sh b/Scripts/bmr-program-run.sh new file mode 100755 index 00000000..8a88669f --- /dev/null +++ b/Scripts/bmr-program-run.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +gdb_screen() +{ + prog=$1 + shift + screen -S :$1 -d -m bash -l -c "echo $*; echo $LIBRARY_PATH; gdb $prog -ex \"run $*\"" +} + +killall -9 bmr-party.x bmr-tparty.x memcheck-amd64-valgrind callgrind-amd64-valgrind bmr-program-party.x bmr-program-tparty.x gdb +dir=$(mktemp -d) +rm -R bmr-log +ln -s $dir bmr-log 2>/dev/null + +ulimit -v $(grep MemTotal /proc/meminfo | awk '{printf "%d", $2/2}'); +ulimit -c 0 + +prog=$1 +n_players=${2:-2} + +netmap=netmap.$(hostname) +echo $[n_players+1] > $netmap +for i in $(seq 0 $n_players); do + echo 127.0.0.1 $[10000+i] >> $netmap +done + +$prefix ./bmr-program-tparty.x $prog $netmap 2>&1 &> bmr-log/t & +for i in $(seq $[n_players-1]); do + $prefix ./bmr-program-party.x $i $prog $netmap 2>&1 &> bmr-log/$i & +done +$prefix ./bmr-program-party.x $n_players $prog $netmap 2>&1 | tee bmr-log/$n_players diff --git a/Scripts/gen_input_f2n.cpp b/Scripts/gen_input_f2n.cpp index 27364008..1c179434 100644 --- a/Scripts/gen_input_f2n.cpp +++ b/Scripts/gen_input_f2n.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include #include diff --git a/Scripts/gen_input_fp.cpp b/Scripts/gen_input_fp.cpp index 64dfb4e2..cd293de2 100644 --- a/Scripts/gen_input_fp.cpp +++ b/Scripts/gen_input_fp.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include #include diff --git a/Scripts/run-common.sh b/Scripts/run-common.sh index 88f94c37..bf01fc66 100644 --- a/Scripts/run-common.sh +++ b/Scripts/run-common.sh @@ -1,4 +1,4 @@ -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt run_player() { diff --git a/Scripts/run-online.sh b/Scripts/run-online.sh index e688bc9a..e4a1fe1e 100755 --- a/Scripts/run-online.sh +++ b/Scripts/run-online.sh @@ -1,6 +1,6 @@ #!/bin/bash -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt HERE=$(cd `dirname $0`; pwd) SPDZROOT=$HERE/.. diff --git a/Scripts/setup-online.sh b/Scripts/setup-online.sh index 97df04f3..892e93df 100755 --- a/Scripts/setup-online.sh +++ b/Scripts/setup-online.sh @@ -1,6 +1,6 @@ #!/bin/bash -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt HERE=$(cd `dirname $0`; pwd) SPDZROOT=$HERE/.. diff --git a/Server.cpp b/Server.cpp index 78ba40a8..cadd0760 100644 --- a/Server.cpp +++ b/Server.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Server.cpp diff --git a/Tools/Commit.cpp b/Tools/Commit.cpp index c0896dc1..74136865 100644 --- a/Tools/Commit.cpp +++ b/Tools/Commit.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Commit.h" diff --git a/Tools/Commit.h b/Tools/Commit.h index 5e74dd53..842a5c7b 100644 --- a/Tools/Commit.h +++ b/Tools/Commit.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _Commit #define _Commit diff --git a/Tools/Config.cpp b/Tools/Config.cpp index f773c4c4..d2c629da 100644 --- a/Tools/Config.cpp +++ b/Tools/Config.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt // Client key file format: // X25519 Public Key diff --git a/Tools/Config.h b/Tools/Config.h index c5c925b7..95787a43 100644 --- a/Tools/Config.h +++ b/Tools/Config.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Tools/octetStream.h" #include "Networking/Player.h" diff --git a/Tools/FlexBuffer.cpp b/Tools/FlexBuffer.cpp new file mode 100644 index 00000000..6c722e90 --- /dev/null +++ b/Tools/FlexBuffer.cpp @@ -0,0 +1,109 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * FlexBuffer.cpp + * + */ + +#include "FlexBuffer.h" +#include +#include +#include "BMR/network/utils.h" +using namespace std; + +#ifndef BUFFER_DIR +#define BUFFER_DIR "/tmp" +#endif + +ReceivedMsgStore::~ReceivedMsgStore() +{ + cout << "Stored " << (double)total_size / 1e9 << " GB in " + << push_timer.elapsed() << " seconds and retrieved them in " + << pop_timer.elapsed() << " seconds " << endl; +} + +void ReceivedMsgStore::push(ReceivedMsg& msg) +{ +#ifdef DEBUG_STORE + cout << "pushing msg of length " << msg.size() << endl; + //phex(msg.data(), min(100UL, msg.size())); +#endif + TimeScope ts(push_timer); + total_size += msg.size(); + if (mem_size != N and files.empty()) + { + mem[(start + mem_size) % N] = msg; + mem_size++; + } + else + { + char filename[1000]; + sprintf(filename, "%s/%d.XXXXXX", BUFFER_DIR, getpid()); + FILE* file = fdopen(mkstemp(filename), "w"); + if (!file) + throw runtime_error("can't open file"); + size_t len = msg.size(); + size_t ptr = msg.ptr - msg.buf; + if (fwrite(&len, sizeof(len), 1, file) != 1) + throw runtime_error("can't write"); + if (fwrite(&ptr, sizeof(len), 1, file) != 1) + throw runtime_error("can't write"); + if (len != 0) + if (fwrite(msg.data(), msg.size(), 1, file) != 1) + throw runtime_error("can't write"); + if (fclose(file) != 0) + throw runtime_error("can't close"); + files.push_back(filename); + } +} + +bool ReceivedMsgStore::pop(ReceivedMsg& msg) +{ + TimeScope ts(pop_timer); + if (mem_size != 0) + { + msg = mem[start]; + start = (start + 1) % N; + mem_size--; +#ifdef DEBUG_STORE + cout << "popping from memory msg of length " << msg.size() << endl; + //phex(msg.data(), min(100UL, msg.size())); +#endif + return true; + } + else if (!files.empty()) + { + string filename = files.front(); + FILE* file = fopen(filename.c_str(), "r"); + files.pop_front(); + fseek(file, 0, SEEK_SET); + size_t len; + if (fread(&len, sizeof(len), 1, file) != 1) + { + perror("can't read length"); + throw runtime_error("can't read length"); + } + msg.resize(len); + size_t ptr; + if (fread(&ptr, sizeof(len), 1, file) != 1) + { + perror("can't read length"); + throw runtime_error("can't read length"); + } + msg.ptr = msg.buf + ptr; + if (len != 0) + if (fread(msg.data(), len, 1, file) != 1) + { + perror("can't read data"); + throw runtime_error("can't read data"); + } + fclose(file); + remove(filename.c_str()); +#ifdef DEBUG_FLEXBUF + cout << "popping from disk msg of length " << msg.size() << endl; + phex(msg.data(), min(100UL, msg.size())); +#endif + return true; + } + return false; +} diff --git a/Tools/FlexBuffer.h b/Tools/FlexBuffer.h new file mode 100644 index 00000000..5e26c6e8 --- /dev/null +++ b/Tools/FlexBuffer.h @@ -0,0 +1,214 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * FlexBuffer.h + * + */ + +#ifndef TOOLS_FLEXBUFFER_H_ +#define TOOLS_FLEXBUFFER_H_ + +#include "Tools/avx_memcpy.h" +#include "Tools/time-func.h" + +#include +#include +#include +#include +using namespace std; + +class FlexBuffer +{ +protected: + char* buf, *ptr; + size_t len, max_len; + void del(); + void reset() { buf = ptr = 0; len = max_len = 0; } +public: + FlexBuffer() : buf(0), ptr(0), len(0), max_len(0) {} + FlexBuffer(const FlexBuffer&); + ~FlexBuffer() { del(); } + void operator=(FlexBuffer& msg); + char* data() { return buf; } + const char* data() const { return buf; } + size_t size() const { return len; } + size_t capacity() const { return max_len; } +}; + +class ReceivedMsg : public virtual FlexBuffer +{ + friend class ReceivedMsgStore; + +public: + void reset_head() { ptr = buf; } + void resize(size_t new_len); + void unserialize(void* output, size_t size); + template + void unserialize(T& output); + template + void nonavx_unserialize(T& output); + char* consume(size_t l) { check_buffer(l); char* res = ptr; ptr += l; return res; } + char pop_front() { check_buffer(1); return *ptr++; } + size_t left() { return len - (ptr - buf); } + void check_buffer(size_t size); +}; + +class SendBuffer : public virtual FlexBuffer +{ +public: + void resize(size_t new_len); + void resize_copy(size_t new_max_len); + void clear() { len = 0; } + const char& operator[](size_t i) { return data()[i]; } + void push_back(char c) { serialize(c); } + template + void serialize(const T& source) { serialize(&source, sizeof(T)); } + void serialize(const void* source, size_t size); + void allocate(size_t size); + template + void serialize_no_allocate(const T& source); + void serialize_no_allocate(const void* source, size_t size); +}; + +class LocalBuffer : public ReceivedMsg, public SendBuffer +{ +}; + +class ReceivedMsgStore +{ + static const int N = 1; + ReceivedMsg mem[N]; + int start, mem_size; + deque files; + size_t total_size; + Timer push_timer, pop_timer; +public: + ReceivedMsgStore() : start(0), mem_size(0), total_size(0) {} + ~ReceivedMsgStore(); + void push(ReceivedMsg& msg); + bool pop(ReceivedMsg& msg); + bool empty() { return mem_size == 0 and files.empty(); } +}; + +inline FlexBuffer::FlexBuffer(const FlexBuffer& msg) +{ + if (msg.buf) + throw runtime_error("can only copy empty buffers"); + reset(); +} + +inline void FlexBuffer::operator=(FlexBuffer& msg) +{ + if (this != &msg) + { + del(); + buf = msg.buf; + ptr = msg.ptr; + len = msg.len; + max_len = msg.max_len; +#ifdef DEBUG_FLEXBUF + cout << "moved " << (void*)buf << " " << (void*)msg.buf << " from " << &msg << " to " << this << endl; +#endif + msg.reset(); + } +} + +inline void ReceivedMsg::resize(size_t new_len) +{ + if (new_len > max_len) + { + del(); + max_len = new_len; + buf = new char[max_len]; +#ifdef DEBUG_FLEXBUF + cout << "allocated " << (void*)buf << " for " << this << endl; +#endif + } + len = new_len; + ptr = buf; +} + +inline void FlexBuffer::del() +{ +#ifdef DEBUG_FLEXBUF + printf("delete 0x%x for 0x%x\n", buf, this); +#endif + if (buf) + delete[] buf; + reset(); +} + +inline void ReceivedMsg::unserialize(void* output, size_t size) +{ + check_buffer(size); + avx_memcpy(output, ptr, size); + ptr += size; +} + +template +inline void ReceivedMsg::unserialize(T& output) +{ + unserialize(&output, sizeof(T)); +} + +template +inline void ReceivedMsg::nonavx_unserialize(T& output) +{ + check_buffer(sizeof(T)); + memcpy(&output, ptr, sizeof(T)); + ptr += sizeof(T); +} + +inline void SendBuffer::resize(size_t new_size) +{ + while (size() < new_size) + push_back(0); +} + +inline void SendBuffer::resize_copy(size_t new_max_len) +{ + char* old = buf; + max_len = new_max_len; + buf = new char[max_len]; + if (old) + { + avx_memcpy(buf, old, len); + delete[] old; + } + ptr = buf + (ptr - old); +} + +inline void SendBuffer::serialize(const void* source, size_t size) +{ + allocate(size); + serialize_no_allocate(source, size); +} + +inline void SendBuffer::allocate(size_t size) +{ + if (len + size > max_len) + resize_copy(2 * (len + size)); +} + +template +inline void SendBuffer::serialize_no_allocate(const T& source) +{ + serialize_no_allocate(&source, sizeof(T)); +} + +inline void SendBuffer::serialize_no_allocate(const void* source, size_t size) +{ + avx_memcpy(buf + len, source, size); + len += size; +} + +inline void ReceivedMsg::check_buffer(size_t size) +{ + (void)size; +#ifdef CHECK_BUFFER + if (ptr + size > buf + len) + throw overflow_error("not enough data in buffer"); +#endif +} + +#endif /* TOOLS_FLEXBUFFER_H_ */ diff --git a/Tools/Lock.cpp b/Tools/Lock.cpp index 7d89c138..e340d2a8 100644 --- a/Tools/Lock.cpp +++ b/Tools/Lock.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Lock.cpp diff --git a/Tools/Lock.h b/Tools/Lock.h index 81c39c08..ed53758c 100644 --- a/Tools/Lock.h +++ b/Tools/Lock.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Lock.h diff --git a/Tools/MMO.cpp b/Tools/MMO.cpp index 42160805..bf8ea26c 100644 --- a/Tools/MMO.cpp +++ b/Tools/MMO.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * MMO.cpp diff --git a/Tools/MMO.h b/Tools/MMO.h index dd331902..3e7af72b 100644 --- a/Tools/MMO.h +++ b/Tools/MMO.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * MMO.h diff --git a/Tools/MemoryUsage.h b/Tools/MemoryUsage.h index 56f076b1..05019b5a 100644 --- a/Tools/MemoryUsage.h +++ b/Tools/MemoryUsage.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * MemoryUsage.h diff --git a/Tools/OfflineMachineBase.cpp b/Tools/OfflineMachineBase.cpp index c4839194..9f7438d4 100644 --- a/Tools/OfflineMachineBase.cpp +++ b/Tools/OfflineMachineBase.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OfflineMachineBase.cpp diff --git a/Tools/OfflineMachineBase.h b/Tools/OfflineMachineBase.h index d002a070..8cb8af63 100644 --- a/Tools/OfflineMachineBase.h +++ b/Tools/OfflineMachineBase.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OfflineMachineBase.h diff --git a/Tools/Signal.cpp b/Tools/Signal.cpp index c449291b..4f79f034 100644 --- a/Tools/Signal.cpp +++ b/Tools/Signal.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Signal.cpp diff --git a/Tools/Signal.h b/Tools/Signal.h index 8196d4c0..cbe0fbc7 100644 --- a/Tools/Signal.h +++ b/Tools/Signal.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * Signal.h diff --git a/Tools/WaitQueue.h b/Tools/WaitQueue.h index 2b50f3eb..7c2aae13 100644 --- a/Tools/WaitQueue.h +++ b/Tools/WaitQueue.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * WaitQueue.h @@ -79,6 +79,21 @@ public: return running; } + bool pop_dont_stop(T& value) + { + lock(); + if (running and queue.size() == 0) + wait(); + bool something_for_you = queue.size() > 0; + if (something_for_you) + { + value = queue.front(); + queue.pop_front(); + } + unlock(); + return something_for_you; + } + void stop() { lock(); diff --git a/Tools/Worker.h b/Tools/Worker.h new file mode 100644 index 00000000..07c0b418 --- /dev/null +++ b/Tools/Worker.h @@ -0,0 +1,63 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * Worker.h + * + */ + +#ifndef TOOLS_WORKER_H_ +#define TOOLS_WORKER_H_ + +#include "WaitQueue.h" + +template +class Worker +{ + pthread_t thread; + WaitQueue input; + WaitQueue output; + Timer timer; + + static void* run_thread(void* worker) + { + ((Worker*)worker)->run(); + return 0; + } + + void run() + { + T* job = 0; + while (input.pop(job)) + { + TimeScope ts(timer); + output.push(job->run()); + } + } + +public: + Worker() : timer(CLOCK_THREAD_CPUTIME_ID) + { + pthread_create(&thread, 0, Worker::run_thread, this); + } + + ~Worker() + { + input.stop(); + pthread_join(thread, 0); + cout << "Worker time: " << timer.elapsed() << endl; + } + + void request(T& job) + { + input.push(&job); + } + + int done() + { + int res = 0; + output.pop(res); + return res; + } +}; + +#endif /* TOOLS_WORKER_H_ */ diff --git a/Tools/aes-ni.cpp b/Tools/aes-ni.cpp index bebde506..fbfdef9a 100644 --- a/Tools/aes-ni.cpp +++ b/Tools/aes-ni.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "aes.h" diff --git a/Tools/aes.cpp b/Tools/aes.cpp index 45d4e47a..d3d8dd9e 100644 --- a/Tools/aes.cpp +++ b/Tools/aes.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "aes.h" diff --git a/Tools/aes.h b/Tools/aes.h index 2b6424c5..c94f7d41 100644 --- a/Tools/aes.h +++ b/Tools/aes.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef __AES_H #define __AES_H diff --git a/Tools/avx_memcpy.h b/Tools/avx_memcpy.h index 94868803..63d14dde 100644 --- a/Tools/avx_memcpy.h +++ b/Tools/avx_memcpy.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * memcpy.h diff --git a/Tools/benchmarking.h b/Tools/benchmarking.h index e3681b68..5321bbdc 100644 --- a/Tools/benchmarking.h +++ b/Tools/benchmarking.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * benchmarking.h diff --git a/Tools/ezOptionParser.h b/Tools/ezOptionParser.h index 78c2e8ed..f9264445 100644 --- a/Tools/ezOptionParser.h +++ b/Tools/ezOptionParser.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* This file is part of ezOptionParser. See MIT-LICENSE. diff --git a/Tools/int.h b/Tools/int.h index 00d43d5c..ea4a07c4 100644 --- a/Tools/int.h +++ b/Tools/int.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * int.h diff --git a/Tools/mkpath.cpp b/Tools/mkpath.cpp index 1b2e2ab3..0e2f233b 100644 --- a/Tools/mkpath.cpp +++ b/Tools/mkpath.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Tools/mkpath.h" #include diff --git a/Tools/mkpath.h b/Tools/mkpath.h index ce738bc1..944bf16d 100644 --- a/Tools/mkpath.h +++ b/Tools/mkpath.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef TOOLS_MKPATH_H_ #define TOOLS_MKPATH_H_ diff --git a/Tools/names.cpp b/Tools/names.cpp index 6db132ed..7137f548 100644 --- a/Tools/names.cpp +++ b/Tools/names.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Processor/Data_Files.h" diff --git a/Tools/octetStream.cpp b/Tools/octetStream.cpp index 2842dbcb..9688b238 100644 --- a/Tools/octetStream.cpp +++ b/Tools/octetStream.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include @@ -11,6 +11,7 @@ #include "Exceptions/Exceptions.h" #include "Networking/data.h" #include "Math/bigint.h" +#include "Tools/time-func.h" void octetStream::clear() @@ -140,7 +141,7 @@ void octetStream::store_int(size_t l, int n_bytes) void octetStream::store(int l) { resize(len+4); - INT_TO_BYTES(data+len,l); + encode_length(data+len,l,4); len+=4; } @@ -154,7 +155,7 @@ size_t octetStream::get_int(int n_bytes) void octetStream::get(int& l) { - l=BYTES_TO_INT(data+ptr); + l=decode_length(data+ptr,4); ptr+=4; } @@ -193,6 +194,69 @@ void octetStream::get(bigint& ans) } +void octetStream::exchange(int send_socket, int receive_socket, octetStream& receive_stream) +{ + send(send_socket, len, LENGTH_SIZE); + const size_t buffer_size = 100000; + size_t sent = 0, received = 0; + bool length_received = false; + size_t new_len = 0; +#ifdef TIME_ROUNDS + Timer recv_timer; +#endif + while (received < new_len or sent < len or not length_received) + { + if (sent < len) + { + size_t to_send = min(buffer_size, len - sent); + send(send_socket, data + sent, to_send); + sent += to_send; + } + + // avoid extra branching, false before length received + if (received < new_len) + { + // same buffer for sending and receiving + // only receive up to already sent data + // or when all is sent + size_t to_receive = 0; + if (sent == len) + to_receive = new_len - received; + else if (sent > received) + to_receive = sent - received; + if (to_receive > 0) + { +#ifdef TIME_ROUNDS + TimeScope ts(recv_timer); +#endif + received += receive_non_blocking(receive_socket, + receive_stream.data + received, to_receive); + } + } + else if (not length_received) + { +#ifdef TIME_ROUNDS + TimeScope ts(recv_timer); +#endif + octet blen[LENGTH_SIZE]; + if (receive_all_or_nothing(receive_socket,blen,LENGTH_SIZE) == LENGTH_SIZE) + { + new_len=decode_length(blen,sizeof(blen)); + receive_stream.resize(max(new_len, len)); + length_received = true; + } + } + } + +#ifdef TIME_ROUNDS + cout << "Exchange time: " << recv_timer.elapsed() << " seconds to receive " + << 1e-3 * new_len << " KB" << endl; +#endif + receive_stream.len = new_len; + receive_stream.reset_read_head(); +} + + void octetStream::store(const vector& v) { store(v.size()); @@ -211,34 +275,6 @@ void octetStream::get(vector& v) } -void octetStream::exchange(int send_socket, int receive_socket) -{ - send(send_socket, len, LENGTH_SIZE); - size_t new_len; - receive(receive_socket, new_len, LENGTH_SIZE); - if (new_len > mxlen) - resize_precise(max(new_len, len)); - const size_t buffer_size = 100000; - size_t sent = 0, received = 0; - while (sent < len or received < new_len) - { - if (sent < len) - { - size_t to_send = min(buffer_size, len - sent); - send(send_socket, data + sent, to_send); - sent += to_send; - } - if (received < new_len) - { - size_t to_receive = min(buffer_size, new_len - received); - receive(receive_socket, data + received, to_receive); - received += to_receive; - } - } - len = new_len; - reset_read_head(); -} - // Construct the ciphertext as `crypto_secretbox(pt, counter||random)` void octetStream::encrypt_sequence(const octet* key, uint64_t counter) { diff --git a/Tools/octetStream.h b/Tools/octetStream.h index 65b904d6..2db7a7ce 100644 --- a/Tools/octetStream.h +++ b/Tools/octetStream.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _octetStream #define _octetStream @@ -21,6 +21,7 @@ #include "Networking/data.h" #include "Networking/sockets.h" +#include "Tools/avx_memcpy.h" #include #include @@ -63,7 +64,7 @@ class octetStream bool done() const { return ptr == len; } bool empty() const { return len == 0; } - int left() const { return len - ptr; } + size_t left() const { return len - ptr; } octetStream hash() const; // output must have length at least HASH_SIZE @@ -88,6 +89,7 @@ class octetStream // Append with no padding for decoding void append(const octet* x,const size_t l); + void append_no_resize(const octet* x,const size_t l); // Read l octets, with no padding for decoding void consume(octet* x,const size_t l); // Return pointer to next l octets and advance pointer @@ -144,11 +146,12 @@ class octetStream void encrypt(const octet* key); void decrypt(const octet* key); - void exchange(int send_socket, int receive_socket); - void input(istream& s); void output(ostream& s); + void exchange(int send_socket, int receive_socket) { exchange(send_socket, receive_socket, *this); } + void exchange(int send_socket, int receive_socket, octetStream& receive_stream); + friend ostream& operator<<(ostream& s,const octetStream& o); friend class PRNG; }; @@ -182,14 +185,19 @@ inline void octetStream::append(const octet* x, const size_t l) { if (len+l>mxlen) resize(len+l); - memcpy(data+len,x,l*sizeof(octet)); + avx_memcpy(data+len,x,l*sizeof(octet)); len+=l; } +inline void octetStream::append_no_resize(const octet* x, const size_t l) +{ + avx_memcpy(data+len,x,l*sizeof(octet)); + len+=l; +} inline void octetStream::consume(octet* x,const size_t l) { - memcpy(x,data+ptr,l*sizeof(octet)); + avx_memcpy(x,data+ptr,l*sizeof(octet)); ptr+=l; } diff --git a/Tools/parse.h b/Tools/parse.h index 59e6c6b5..54e5a08d 100644 --- a/Tools/parse.h +++ b/Tools/parse.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * parse.h diff --git a/Tools/pprint.h b/Tools/pprint.h index 8ac72ae7..fe0a6a6a 100644 --- a/Tools/pprint.h +++ b/Tools/pprint.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include diff --git a/Tools/random.cpp b/Tools/random.cpp index 2b1b6867..01c757e0 100644 --- a/Tools/random.cpp +++ b/Tools/random.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Tools/random.h" @@ -138,26 +138,6 @@ unsigned int PRNG::get_uint() -unsigned char PRNG::get_uchar() -{ - if (cnt>=RAND_SIZE) { next(); } - unsigned char ans=random[cnt]; - cnt++; - // print_state(); cout << " UCHA " << (int) ans << endl; - return ans; -} - - -__m128i PRNG::get_doubleword() -{ - if (cnt > RAND_SIZE - 16) - next(); - __m128i ans = _mm_loadu_si128((__m128i*)&random[cnt]); - cnt += 16; - return ans; -} - - void PRNG::get_octetStream(octetStream& ans,int len) { ans.resize(len); @@ -168,22 +148,6 @@ void PRNG::get_octetStream(octetStream& ans,int len) } -void PRNG::get_octets(octet* ans,int len) -{ - int pos=0; - while (len) - { - int step=min(len,RAND_SIZE-cnt); - memcpy(ans+pos,random+cnt,step); - pos+=step; - len-=step; - cnt+=step; - if (cnt==RAND_SIZE) - next(); - } -} - - bigint PRNG::randomBnd(const bigint& B, bool positive) { bigint x; diff --git a/Tools/random.h b/Tools/random.h index aeb23e89..8b510410 100644 --- a/Tools/random.h +++ b/Tools/random.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _random #define _random @@ -87,4 +87,41 @@ class PRNG { return seed; } }; + +inline unsigned char PRNG::get_uchar() +{ + if (cnt>=RAND_SIZE) { next(); } + unsigned char ans=random[cnt]; + cnt++; + // print_state(); cout << " UCHA " << (int) ans << endl; + return ans; +} + + +inline __m128i PRNG::get_doubleword() +{ + if (cnt > RAND_SIZE - 16) + next(); + __m128i ans = _mm_loadu_si128((__m128i*)&random[cnt]); + cnt += 16; + return ans; +} + + +inline void PRNG::get_octets(octet* ans,int len) +{ + int pos=0; + while (len) + { + int step=min(len,RAND_SIZE-cnt); + avx_memcpy(ans+pos,random+cnt,step); + pos+=step; + len-=step; + cnt+=step; + if (cnt==RAND_SIZE) + next(); + } +} + + #endif diff --git a/Tools/sha1.cpp b/Tools/sha1.cpp index e285f261..e5468439 100644 --- a/Tools/sha1.cpp +++ b/Tools/sha1.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * SHA1 routine optimized to do word accesses rather than byte accesses, diff --git a/Tools/sha1.h b/Tools/sha1.h index d7451bc9..b1f87cc0 100644 --- a/Tools/sha1.h +++ b/Tools/sha1.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _SHA1 #define _SHA1 diff --git a/Tools/time-func.cpp b/Tools/time-func.cpp index 509eea67..253d9e3d 100644 --- a/Tools/time-func.cpp +++ b/Tools/time-func.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Tools/time-func.h" diff --git a/Tools/time-func.h b/Tools/time-func.h index a56091bf..916871fa 100644 --- a/Tools/time-func.h +++ b/Tools/time-func.h @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #ifndef _timer #define _timer diff --git a/bmr-program-party.cpp b/bmr-program-party.cpp new file mode 100644 index 00000000..b4813bb8 --- /dev/null +++ b/bmr-program-party.cpp @@ -0,0 +1,14 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * bmr-program-party.cpp + * + */ + +#include "BMR/Party.h" + +int main(int argc, char** argv) +{ + ProgramParty party(argc, argv); + party.Start(); +} diff --git a/bmr-program-tparty.cpp b/bmr-program-tparty.cpp new file mode 100644 index 00000000..8cda80a4 --- /dev/null +++ b/bmr-program-tparty.cpp @@ -0,0 +1,14 @@ +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt + +/* + * bmr-program-tparty.cpp + * + */ + +#include "BMR/TrustedParty.h" + +int main(int argc, char** argv) +{ + TrustedProgramParty party(argc, argv); + party.Start(); +} diff --git a/check-passive.cpp b/check-passive.cpp index 3084bb99..accbbf05 100644 --- a/check-passive.cpp +++ b/check-passive.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "Math/gf2n.h" #include "Math/gfp.h" diff --git a/client-setup.cpp b/client-setup.cpp index 86b4d006..98c1a169 100644 --- a/client-setup.cpp +++ b/client-setup.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt // Preprocessing stage to: // Create the public/private key pairs for each client diff --git a/cnc-offline.cpp b/cnc-offline.cpp index ad042cc9..c94049ed 100644 --- a/cnc-offline.cpp +++ b/cnc-offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * cnc-offline.cpp diff --git a/compile.py b/compile.py index 653f8100..dd3a64d8 100755 --- a/compile.py +++ b/compile.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# (C) 2018 University of Bristol. See License.txt +# (C) 2018 University of Bristol, Bar-Ilan University. See License.txt # ===== Compiler usage instructions ===== @@ -43,11 +43,8 @@ def main(): parser.add_option("-r", "--noreorder", dest="reorder_between_opens", action="store_false", default=True, help="don't attempt to place instructions between start/stop opens") - parser.add_option("-M", "--preserve-mem-order", action="store_true", - dest="preserve_mem_order", default=True, - help="preserve order of memory instructions; possible efficiency loss") parser.add_option("-O", "--optimize-hard", action="store_false", - dest="preserve_mem_order", default=True, + dest="preserve_mem_order", default=False, help="don't preserve order of memory instructions; possible loss of correctness") parser.add_option("-u", "--noreallocate", action="store_true", dest="noreallocate", default=False, help="don't reallocate") diff --git a/ot-offline.cpp b/ot-offline.cpp index 94cc9453..d0bfec8b 100644 --- a/ot-offline.cpp +++ b/ot-offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * OT-Offline.cpp diff --git a/pairwise-offline.cpp b/pairwise-offline.cpp index b963e7fc..bcfd525f 100644 --- a/pairwise-offline.cpp +++ b/pairwise-offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt #include "FHEOffline/PairwiseMachine.h" #include diff --git a/simple-offline.cpp b/simple-offline.cpp index 071fa5c7..07e01dbd 100644 --- a/simple-offline.cpp +++ b/simple-offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * simple-offline.cpp diff --git a/spdz2-offline.cpp b/spdz2-offline.cpp index 07daccbe..b9c09ec6 100644 --- a/spdz2-offline.cpp +++ b/spdz2-offline.cpp @@ -1,4 +1,4 @@ -// (C) 2018 University of Bristol. See License.txt +// (C) 2018 University of Bristol, Bar-Ilan University. See License.txt /* * spdz2-offline.cpp diff --git a/tutorial.md b/tutorial.md index 42e63d26..b09695e2 100644 --- a/tutorial.md +++ b/tutorial.md @@ -1,4 +1,4 @@ -(C) 2018 University of Bristol. See License.txt +(C) 2018 University of Bristol, Bar-Ilan University. See License.txt Suppose we want to add 2 integers mod p in clear, where p has 128 bits and compute over 2 parties inputs: P0, P1.