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.
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)
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
Public Members
-
vector<client_socket*> sockets¶
Sockets for cleartext communication
-
octetStream specification¶
Specification of computation domain
-
Client(const vector<string> &hostnames, int port_base, int my_client_id)¶