Networking

All protocols in MP-SPDZ rely on point-to-point connections between all pairs of parties. This is realized using TCP, which means that every party must be reachable under at least one TCP port. The default is to set this port to a base plus the player number. This allows for easily running all parties on the same host. The base defaults to 5000, which can be changed with the command-line option --portnumbase. However, the scripts in Scripts use a random base port number, which can be changed using the same option.

There are two ways of communicating hosts and individually setting ports:

  1. All parties first connect to a coordination server, which broadcasts the data for all parties. This is the default with the coordination server being run as a thread of party 0. The hostname of the coordination server has to be given with the command-line parameter --hostname, and the coordination server runs on the base port number, thus defaulting to 5000. Furthermore, you can specify a party’s listening port using --my-port.

  2. The parties read the information from a local file, which needs to be the same everywhere. The file can be specified using --ip-file-name and has the following format:

    <host0>[:<port0>]
    <host1>[:<port1>]
    ...
    

    The hosts can be both hostnames and IP addresses. If not given, the ports default to base plus party number.

Whether or not encrypted connections are used depends on the security model of the protocol. Honest-majority protocols default to encrypted whereas dishonest-majority protocols default to unencrypted. You change this by either using --encrypted/-e or --unencrypted/-u.

If using encryption, the certificates (Player-Data/*.pem) must be the same on all hosts, and you have to run c_rehash Player-Data on all of them. Scripts/setup-ssl.sh can be used to generate the necessary certificates. The common name has to be P<player number> for computing parties and C<client number> for clients.

Internal Infrastructure

The internal networking infrastructure of MP-SPDZ reflects the needs of the various multi-party computation. For example, some protocols require a simultaneous broadcast from all parties whereas other protocols require that every party sends different information to different parties (include none at all). The infrastructure makes sure to send and receive in parallel whenever possible.

All communication is handled through two subclasses of Player defined in Networking/Player.h. PlainPlayer communicates in cleartext while CryptoPlayer uses TLS encryption. The former uses the same BSD socket for sending and receiving but the latter uses two different connections for sending and receiving. This is because TLS communication is never truly one-way due key renewals etc., so the only way for simultaneous sending and receiving we found was to use two connections in two threads.

If you wish to use a different networking facility, we recommend to subclass Player and fill in the virtual-only functions required by the compiler (e.g., send_to_no_stats() for sending to one other party). Note that not all protocols require all functions, so you only need to properly implement those you need. You can then replace uses of PlainPlayer or CryptoPlayer by your own class. Furthermore, you might need to extend the Names class to suit your purpose. By default, Names manages one TCP port that a party is listening on for connections. If this suits you, you don’t need to change anything

Reference

class Names

Network setup (hostnames and port numbers)

Public Functions

void init(int player, int pnb, int my_port, const char *servername, bool setup_socket = true)

Initialize with central server

Parameters
  • player – my number

  • pnb – base port number (server listens one below)

  • my_port – my port number (DEFAULT_PORT for default, which is base port number plus player number)

  • servername – location of server

  • setup_socket – whether to start listening

inline Names(int player, int pnb, int my_port, const char *servername)
Names(int player, int nplayers, const string &servername, int pnb, int my_port = DEFAULT_PORT)

Initialize with central server running on player 0

Parameters
  • player – my number

  • nplayers – number of players

  • servername – location of player 0

  • pnb – base port number

  • my_port – my port number (DEFAULT_PORT for default, which is base port number plus player number)

void init(int player, int pnb, vector<string> Nms)

Initialize without central server

Parameters
  • player – my number

  • pnb – base port number

  • Nms – locations of all parties

inline Names(int player, int pnb, vector<string> Nms)
void init(int player, int pnb, const string &hostsfile, int players = 0)

Initialize from file. One party per line, format <hostname>[:<port>]

Parameters
  • player – my number

  • pnb – base port number

  • hostsfile – filename

  • players – number of players (0 to take from file)

inline Names(int player, int pnb, const string &hostsfile)
Names(ez::ezOptionParser &opt, int argc, const char **argv, int default_nplayers = 2)

Initialize from command-line options

Parameters
  • opt – option parser instance

  • argc – number of command-line arguments

  • argv – command-line arguments

  • default_nplayers – default number of players (used if not given in arguments)

Names(int my_num = 0, int num_players = 1)
Names(const Names &other)
~Names()
inline int num_players() const
inline int my_num() const
inline const string get_name(int i) const
inline int get_portnum_base() const

Public Static Attributes

static const int DEFAULT_PORT = -1
class Player : public PlayerBase

Abstract class for multi-player communication. *_no_stats functions are called by their equivalents after accounting for communications statistics.

Subclassed by MultiPlayer< int >, MultiPlayer< ssl_socket * >, AllButLastPlayer, MultiPlayer< T >

Public Functions

inline virtual int num_players() const

Get number of players

inline virtual int my_num() const

Get my player number

virtual void send_all(const octetStream &o) const

Send the same to all other players

void send_to(int player, const octetStream &o) const

Send to a specific player

void receive_all(vector<octetStream> &os) const

Receive from all other players. Information from player 0 at os[0] etc.

virtual void receive_player(int i, octetStream &o) const

Receive from a specific player

void send_relative(const vector<octetStream> &o) const

Send to all other players by offset. o[0] gets sent to the next player etc.

void receive_relative(vector<octetStream> &o) const

Receive from all other players by offset. o[0] will contain data from the next player etc.

void receive_relative(int offset, octetStream &o) const

Receive from other player specified by offset. 1 stands for the next player etc.

void exchange(int other, const octetStream &to_send, octetStream &ot_receive) const

Exchange information with one other party, reusing the buffer if possible.

void exchange(int other, octetStream &o) const

Exchange information with one other party, reusing the buffer.

void exchange_relative(int offset, octetStream &o) const

Exchange information with one other party specified by offset, reusing the buffer if possible.

inline virtual void pass_around(octetStream &o, int offset = 1) const

Send information to a party while receiving from another by offset, The default is to send to the next party while receiving from the previous. The buffer is reused.

void pass_around(octetStream &to_send, octetStream &to_receive, int offset) const

Send information to a party while receiving from another by offset. The default is to send to the next party while receiving from the previous.

virtual void unchecked_broadcast(vector<octetStream> &o) const

Broadcast and receive data to/from all players. Assumes o[player_no] contains the data to be broadcast by me.

virtual void Broadcast_Receive(vector<octetStream> &o) const

Broadcast and receive data to/from all players with eventual verification. Assumes o[player_no] contains the data to be broadcast by me.

virtual void Check_Broadcast() const

Run protocol to verify broadcast is correct

virtual void send_receive_all(const vector<octetStream> &to_send, vector<octetStream> &to_receive) const

Send something different to each player.

void send_receive_all(const vector<bool> &senders, const vector<octetStream> &to_send, vector<octetStream> &to_receive) const

Specified senders only send something different to each player.

Parameters
  • senders – set whether a player sends or not, must be equal on all players

  • to_send – data to send by player number

  • to_receive – received data by player number

void send_receive_all(const vector<vector<bool>> &channels, const vector<octetStream> &to_send, vector<octetStream> &to_receive) const

Send something different only one specified channels.

Parameters
  • channelschannel[i][j] indicates whether party i sends to party j

  • to_send – data to send by player number

  • to_receive – received data by player number

virtual void partial_broadcast(const vector<bool> &senders, const vector<bool> &receivers, vector<octetStream> &os) const

Specified senders broadcast information to specified receivers.

Parameters
  • senders – specify which parties do send

  • receivers – specify which parties do send

  • os – data to send at os[my_number], received data elsewhere

template<class T>
class MultiPlayer : public Player

Multi-player communication helper class. T = int for unencrypted BSD sockets and T = ssl_socket* for Boost SSL streams.

class PlainPlayer : public MultiPlayer<int>

Plaintext multi-player communication

Subclassed by ThreadPlayer

Public Functions

PlainPlayer(const Names &Nms, const string &id)

Start a new set of unencrypted connections.

Parameters
  • Nms – network setup

  • id – unique identifier

class CryptoPlayer : public MultiPlayer<ssl_socket*>

Encrypted multi-party communication. Uses OpenSSL and certificates issued to “P<player_no>”. Sending and receiving is done in separate threads to allow for bidirectional communication.

Public Functions

CryptoPlayer(const Names &Nms, const string &id)

Start a new set of encrypted connections.

Parameters
  • Nms – network setup

  • id – unique identifier

virtual void partial_broadcast(const vector<bool> &my_senders, const vector<bool> &my_receivers, vector<octetStream> &os) const

Specified senders broadcast information to specified receivers.

Parameters
  • senders – specify which parties do send

  • receivers – specify which parties do send

  • os – data to send at os[my_number], received data elsewhere

class octetStream

Buffer for network communication with a pointer for sequential reading. When sent over the network or stored in a file, the length is prefixed as eight bytes in little-endian order.

Public Functions

inline void resize(size_t l)

Increase allocation if needed.

void clear()

Free memory.

octetStream(size_t maxlen)

Initial allocation.

octetStream(size_t len, const octet *source)

Initial buffer.

octetStream(const string &other)

Initial buffer.

inline size_t get_ptr() const

Number of bytes already read.

inline size_t get_length() const

Length.

inline size_t get_total_length() const

Length including size tag.

inline size_t get_max_length() const

Allocation.

inline octet *get_data() const

Data pointer.

inline octet *get_data_ptr() const

Read pointer.

inline bool done() const

Whether done reading.

inline bool empty() const

Whether empty.

inline size_t left() const

Bytes left to read.

string str() const

Convert to string.

octetStream hash() const

Hash content.

void concat(const octetStream &os)

Append other buffer.

inline void reset_read_head()

Reset reading.

inline void reset_write_head()

Set length to zero but keep allocation.

inline bool operator==(const octetStream &a) const

Equality test.

void append_random(size_t num)

Append num random bytes.

inline void append(const octet *x, const size_t l)

Append l bytes from x

inline void consume(octet *x, const size_t l)

Read l bytes to x

inline void store(unsigned int a)

Append 4-byte integer.

void store(int a)

Append 4-byte integer.

inline void get(unsigned int &a)

Read 4-byte integer.

void get(int &a)

Read 4-byte integer.

inline void store(size_t a)

Append 8-byte integer.

inline void get(size_t &a)

Read 8-byte integer.

inline void store_int(size_t a, int n_bytes)

Append integer of n_bytes bytes.

inline size_t get_int(int n_bytes)

Read integer of n_bytes bytes.

template<int N_BYTES>
inline void store_int(size_t a)

Append integer of N_BYTES bytes.

template<int N_BYTES>
inline size_t get_int()

Read integer of N_BYTES bytes.

void store(const bigint &x)

Append big integer.

void get(bigint &ans)

Read big integer.

template<class T>
void store(const T &x)

Append instance of type implementing pack

template<class T>
T get()

Read instance of type implementing unpack

template<class T>
void get(T &ans)

Read instance of type implementing unpack

template<class T>
void store(const vector<T> &v)

Append vector of type implementing pack

template<class T>
void get(vector<T> &v, const T &init = {})

Read vector of type implementing unpack

Parameters
  • v – results

  • init – initialization if required

template<class T>
void get_no_resize(vector<T> &v)

Read vector of type implementing unpack if vector already has the right size

inline void consume(octetStream &s, size_t l)

Read l bytes into separate buffer.

void store(const string &str)

Append string.

void get(string &str)

Read string.

template<class T>
inline void Send(T socket_num) const

Send on socket_num

template<class T>
inline void Receive(T socket_num)

Receive on socket_num, overwriting current content.

void input(istream &s)

Input from stream, overwriting current content.

void output(ostream &s)

Output to stream.

template<class T>
inline void exchange(T send_socket, T receive_socket)

Send on socket_num while receiving on receiving_socket, overwriting current content

template<class T>
void exchange(T send_socket, T receive_socket, octetStream &receive_stream) const

Send this buffer on socket_num while receiving to receive_stream on receiving_socket