Input/Output

This section gives an overview over the input/output facilities.

Private Inputs from Computing Parties

All secret types have an input function (e.g. Compiler.types.sint.get_input_from() or Compiler.types.sfix.get_input_from()). Inputs are read as whitespace-separated text in order (independent of the data type) from Player-Data/Input-P<player>-<thread>, where thread is 0 for the main thread. You can change the prefix (Player-Data/Input) using the -IF option on the virtual machine binary. You can also use -I to read inputs from the command line. Compiler.types.sint.input_tensor_from() and Compiler.types.sfix.input_tensor_from() allow inputting a tensor.

Compile-Time Data via Private Input

input_tensor_via() is a convenience function that allows to use data available at compile-time via private input.

Public Inputs

All types can be assigned a hard-coded value at compile time, e.g. sint(1). This is impractical for larger amounts of data. foreach_enumerate() provides a facility for this case. It uses public_input internally, which reads from Programs/Public-Input/<progname>.

Public Outputs

By default, print_ln() and related functions only output to the terminal on party 0. This allows to run several parties in one terminal without spoiling the output. You can use interactive mode with option -I in order to output on all parties or -OF . to activate the output without interactive mode. Note that the former also causes to inputs from the command line unless you specify -IF as well. You can also specify a file prefix with -OF, so that outputs are written to <prefix>-P<player>-<thread>.

Private Outputs to Computing Parties

Some types provide a function to reveal a value only to a specific party (e.g., Compiler.types.sint.reveal_to()). It can be used conjunction with print_ln_to() in order to output it.

Binary Output

Most types returned by reveal() or reveal_to() feature a binary_output() method, which writes to Player-Data/Binary-Output-P<playerno>-<threadno>. The format is either signed 64-bit integer or double-precision floating-point in machine byte order (usually little endian).

Clients (Non-computing Parties)

Compiler.types.sint.receive_from_client() and Compiler.types.sint.reveal_to_clients() allow communicating securely with the clients. See the relevant section covering both client code and server-side high-level code. Compiler.types.sint.input_tensor_from_client() and Compiler.types.MultiArray.reveal_to_clients(). The same functions are available for sfix and Array, respectively. See also C++ Reference below.

Secret Shares via Socket

Secret can be sent and received via socket by using write_to_socket() and read_from_socket() (and the same functions in sfix). The connections are set up in the same way as in the previous section. See Multinode Computation Example for an example how this is used to distribute every party among multiple nodes. If you use the client interface, you should use the octetStream class for serialization. The format is the same as in the following section.

Secret Shares via Files

Compiler.types.sint.read_from_file() and Compiler.types.sint.write_to_file() allow reading and writing secret shares to and from files. These instructions use Persistence/Transactions-P<playerno>.data. This files use the same header as preprocessing files. The format for the shares data depends on the protocol and is created by the output member function of the relevant share type. It follows the following principles:

  • One share follows the other without metadata.

  • If there is a MAC, it comes after the share.

  • Numbers are stored in little-endian format.

  • Numbers modulo a power of two are stored with the minimal number of bytes.

  • Numbers modulo a prime are stored in Montgomery representation in blocks of eight bytes.

Another possibility for persistence between program runs is to use the fact that the memory is stored in Player-Data/Memory-<protocol>-P<player> at the end of a run. The best way to use this is via the memory access functions like store_in_mem() and load_mem(). Make sure to only use addresses below USER_MEM specified in Compiler/config.py to avoid conflicts with the automatic allocation used for arrays etc. Note also that all types based on sint (e.g., sfix) share the same memory, and that the address is only a base address. This means that vectors will be written to the memory starting at the given address.

Python Trusted Client Tutorial

In this section, we will illustrate how to use the client interface to supplement individual parties in the secure computation. This example consists of ../Programs/Source/personal_client_example.py for the server side and ../ExternalIO/personal-client-example.py for the client side.

The servers start by listening for and accepting one connection:

listen_for_clients(15000)
socket = accept_client_connection(15000)

The clients in turn connect to the server that is assigned to them:

party = int(sys.argv[1])
client = Client(['localhost'], 15000 + party, 0)

party stands for the number of the relevant server. Then, the clients of the of the first two servers sample 1000 random values and send them to their assigned server:

n = 1000
if party < 2:
  client.send_public_inputs(random.gauss(0, 1) * 2 ** 16 for i in range(n))

Note that the values are multiplied by \(2^{16}\) to match the default fixed-point precision.

The first two servers then receive these values, convert them to shares, and then send the shares to their personal client:

n = 1000
for i in range(2):
  x = personal.read_fix_from_socket(i, socket, n)
  sfix(x).write_fully_to_socket(socket)

Note that all servers run this code because they are all involved in the secret-sharing process. If you’re aiming for the secret sharing to happen on the client side, see this section.

The clients receive the shares and sum them pair-wise before sending them back:

x = [client.receive_plain_values() for i in range(2)]
client.send_public_inputs(a + b for a, b in zip(*x))

Note that this works whether the shares have MACs or not because adding shares with MACs amounts to simply adding both.

The servers finally receive the summed values, perform another sum, and output the result:

res = sum(sfix.read_from_socket(socket, n))
print_ln('%s', res.reveal())

Python Reference

class ExternalIO.client.Client(hostnames, port_base, my_client_id)[source]

Client to servers running secure computation. Works both as a client to all parties or a trusted client to a single party.

Parameters
  • hostnames – hostnames or IP addresses to connect to

  • port_base – port number for first hostname, increases by one for every additional hostname

  • my_client_id – number to identify client

receive_outputs(n)[source]

Receive outputs privately from the computation servers. This assumes that the client is connected to all servers.

Parameters

n – number of outputs

receive_plain_values(socket=None)[source]

Receive values in the clear. This works for public inputs to all servers or to send shares to a single server.

Parameters

socket – socket to use (need to specify it there is more than one)

send_private_inputs(values)[source]

Send inputs privately to the computation servers. This assumes that the client is connected to all servers.

Parameters

values – list of input values

send_public_inputs(values)[source]

Send values in the clear. This works for public inputs to all servers or to send shares to a single server.

Parameters

values – list of values

C++ Reference

class Client

Client-side interface

Public Functions

Client(const vector<string> &hostnames, int port_base, int my_client_id)

Start a new set of connections to computing parties.

Parameters
  • hostnames – location of computing parties

  • port_base – port base

  • my_client_id – client identifier

template<class T>
void send_private_inputs(const vector<T> &values)

Securely input private values.

Parameters

values – vector of integer-like values

template<class T, class U = T>
vector<U> receive_outputs(int n)

Securely receive output values.

Parameters

n – number of values

Returns

vector of integer-like values

Public Members

vector<client_socket*> sockets

Sockets for cleartext communication

octetStream specification

Specification of computation domain