Bristol Fashion.

This commit is contained in:
Marcel Keller
2020-04-02 18:06:14 +11:00
parent cb8e46d2f3
commit 24926df83b
98 changed files with 1266 additions and 2657 deletions

View File

@@ -1,4 +1,32 @@
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).
The ExternalIO directory contains an example 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).
## Working Examples
[bankers-bonus-client.cpp](./bankers-bonus-client.cpp) acts as a
client to [bankers_bonus.mpc](../Programs/Source/bankers_bonus.mpc)
and demonstrates sending input and receiving output as described by
[Damgård et al.](https://eprint.iacr.org/2015/1006) The computation
allows up to eight clients to input a number and computes the client
with the largest input. You can run it as follows from the main
directory:
```
make bankers-bonus-client.x
./compile.py bankers_bonus 1
Scripts/setup-ssl.sh <nparties>
Scripts/setup-clients.sh 3
Scripts/<protocol>.sh &
./bankers-bonus-client.x 0 <nparties 100 0 &
./bankers-bonus-client.x 1 <nparties> 200 0 &
./bankers-bonus-client.x 2 <nparties> 50 1
```
This should output that the winning id is 1. Note that the ids have to
be incremental, and the client with the highest id has to input 1 as
the last argument while the others have to input 0 there. Furthermore,
`<nparties>` refers to the number of parties running the computation
not the number of clients, and `<protocol>` can be the name of
protocol script. The setup scripts generate the necessary SSL
certificates and keys. Therefore, if you run the computation on
different hosts, you will have to distribute the `*.pem` files.
## I/O MPC Instructions
@@ -55,49 +83,3 @@ Receive shares of private inputs from a client, blocking on client send. This is
*message_type* - optional integer which will be sent in first 4 bytes of message, to indicate message type to client.
*[inputs]* - returned list of shares of private input.
## Securing communications
Two cryptographic protocols have been implemented for use in particular applications and are included here for completeness:
1. Communication security using a Station to Station key agreement and libsodium Secret Box using a nonce counter for message ordering.
2. Authenticated Diffie-Hellman without message ordering.
Please note these are **NOT** required to allow external client I/O. Your mileage may vary, for example in a web setting TLS may be sufficient to secure communications between processes.
[client-setup.cpp](../client-setup.cpp) is a utility which is run to generate the key material for both the external clients and SPDZ parties for both protocols.
#### MPC instructions
**regint.init_secure_socket**(*regint client_socket_id*, *[regint] public_signing_key*)
STS protocol initiator. Read a client public key for a specified client connection and negotiate a shared key via STS. All subsequent write_socket / read_socket instructions are encrypted / decrypted for replay resistant commsec.
*client_socket_id* - an identifier used to refer to the client socket.
*public_signing_key* - client public key supplied as list of 8 32-bit ints.
**regint.resp_secure_socket**(*regint client_socket_id*, *[regint] public_signing_key*)
STS protocol responder. Read a client public key for a specified client connection and negotiate a shared key via STS. All subsequent write_socket / read_socket instructions are encrypted / decrypted for replay resistant commsec.
*client_socket_id* - an identifier used to refer to the client socket.
*public_signing_key* - client public key supplied as list of 8 32-bit ints.
*[regint public_key]* **regint.read_client_public_key**(*regint client_socket_id*)
Instruction to read the client public key and run setup for the authenticated Diffie-Hellman encryption. All subsequent write_socket instructions are encrypted. Only the sint.read_from_socket instruction is encrypted.
*client_socket_id* - an identifier used to refer to the client socket.
*public_key* - client public key made available to mpc programs as list of 8 32-bit ints.
## Working Examples
See [bankers-bonus-client.cpp](./bankers-bonus-client.cpp) which acts as a client to [bankers_bonus.mpc](../Programs/Source/bankers_bonus.mpc) and demonstrates sending input and receiving output with no communications security.
See [bankers-bonus-commsec-client.cpp](./bankers-bonus-commsec-client.cpp) which acts as a client to [bankers_bonus_commsec.mpc](../Programs/Source/bankers_bonus_commsec.mpc) which runs the same algorithm but includes both the available crypto protocols.
More instructions on how to run these are provided in the *-client files.

View File

@@ -16,11 +16,10 @@
* - share of random value [r]
* - share of winning unique id * random value [w]
* winning unique id is valid if ∑ [y] * ∑ [r] = ∑ [w]
*
* No communications security is used.
*
* To run with 2 parties / SPDZ engines:
* ./Scripts/setup-online.sh to create triple shares for each party (spdz engine).
* ./Scripts/setup-clients.sh to create SSL keys and certificates for clients
* ./compile.py bankers_bonus
* ./Scripts/run-online.sh bankers_bonus to run the engines.
*
@@ -34,6 +33,7 @@
#include "Math/gfp.h"
#include "Math/gf2n.h"
#include "Networking/sockets.h"
#include "Networking/ssl_sockets.h"
#include "Tools/int.h"
#include "Math/Setup.h"
#include "Protocols/fake-stuff.h"
@@ -46,12 +46,13 @@
// Send the private inputs masked with a random value.
// Receive shares of a preprocessed triple from each SPDZ engine, combine and check the triples are valid.
// Add the private input value to triple[0] and send to each spdz engine.
void send_private_inputs(const vector<gfp>& values, vector<int>& sockets, int nparties)
template<class T>
void send_private_inputs(const vector<T>& values, vector<ssl_socket*>& sockets, int nparties)
{
int num_inputs = values.size();
octetStream os;
vector< vector<gfp> > triples(num_inputs, vector<gfp>(3));
vector<gfp> triple_shares(3);
vector< vector<T> > triples(num_inputs, vector<T>(3));
vector<T> triple_shares(3);
// Receive num_inputs triples from SPDZ
for (int j = 0; j < nparties; j++)
@@ -59,6 +60,10 @@ void send_private_inputs(const vector<gfp>& values, vector<int>& sockets, int np
os.reset_write_head();
os.Receive(sockets[j]);
#ifdef VERBOSE_COMM
cerr << "received " << os.get_length() << " from " << j << endl;
#endif
for (int j = 0; j < num_inputs; j++)
{
for (int k = 0; k < 3; k++)
@@ -72,49 +77,30 @@ void send_private_inputs(const vector<gfp>& values, vector<int>& sockets, int np
// Check triple relations (is a party cheating?)
for (int i = 0; i < num_inputs; i++)
{
if (triples[i][0] * triples[i][1] != triples[i][2])
if (T(triples[i][0] * triples[i][1]) != triples[i][2])
{
cerr << triples[i][2] << " != " << triples[i][0] << " * " << triples[i][1] << endl;
cerr << "Incorrect triple at " << i << ", aborting\n";
exit(1);
throw mac_fail();
}
}
// Send inputs + triple[0], so SPDZ can compute shares of each value
os.reset_write_head();
for (int i = 0; i < num_inputs; i++)
{
gfp y = values[i] + triples[i][0];
T y = values[i] + triples[i][0];
y.pack(os);
}
for (int j = 0; j < nparties; j++)
os.Send(sockets[j]);
}
// Assumes that Scripts/setup-online.sh has been run to compute prime
void initialise_fields(const string& dir_prefix)
{
int lg2;
bigint p;
string filename = dir_prefix + "Params-Data";
cout << "loading params from: " << filename << endl;
ifstream inpf(filename.c_str());
if (inpf.fail()) { throw file_error(filename.c_str()); }
inpf >> p;
inpf >> lg2;
inpf.close();
gfp::init_field(p);
gf2n::init_field(lg2);
}
// Receive shares of the result and sum together.
// Also receive authenticating values.
gfp receive_result(vector<int>& sockets, int nparties)
template<class T>
T receive_result(vector<ssl_socket*>& sockets, int nparties)
{
vector<gfp> output_values(3);
vector<T> output_values(3);
octetStream os;
for (int i = 0; i < nparties; i++)
{
@@ -122,20 +108,32 @@ gfp receive_result(vector<int>& sockets, int nparties)
os.Receive(sockets[i]);
for (unsigned int j = 0; j < 3; j++)
{
gfp value;
T value;
value.unpack(os);
output_values[j] += value;
}
}
if (output_values[0] * output_values[1] != output_values[2])
if (T(output_values[0] * output_values[1]) != output_values[2])
{
cerr << "Unable to authenticate output value as correct, aborting." << endl;
exit(1);
throw mac_fail();
}
return output_values[0];
}
template<class T>
void run(int salary_value, vector<ssl_socket*>& sockets, int nparties)
{
// Run the computation
send_private_inputs<T>({salary_value}, sockets, nparties);
cout << "Sent private inputs to each SPDZ engine, waiting for result..." << endl;
// Get the result back (client_id of winning client)
T result = receive_result<T>(sockets, nparties);
cout << "Winning client id is : " << result << endl;
}
int main(int argc, char** argv)
{
@@ -162,34 +160,65 @@ int main(int argc, char** argv)
if (argc > 6)
port_base = atoi(argv[6]);
// init static gfp
string prep_data_prefix = get_prep_dir(nparties, 128, gf2n::default_degree());
initialise_fields(prep_data_prefix);
bigint::init_thread();
// Setup connections from this client to each party socket
vector<int> sockets(nparties);
vector<int> plain_sockets(nparties);
vector<ssl_socket*> sockets(nparties);
ssl_ctx ctx("C" + to_string(my_client_id));
ssl_service io_service;
octetStream specification;
for (int i = 0; i < nparties; i++)
{
set_up_client_socket(sockets[i], host_name.c_str(), port_base + i);
send(sockets[i], (octet*) &my_client_id, sizeof(int));
set_up_client_socket(plain_sockets[i], host_name.c_str(), port_base + i);
send(plain_sockets[i], (octet*) &my_client_id, sizeof(int));
sockets[i] = new ssl_socket(io_service, ctx, plain_sockets[i],
"P" + to_string(i), "C" + to_string(my_client_id), true);
if (i == 0)
specification.Receive(sockets[0]);
octetStream os;
os.store(finish);
os.Send(sockets[i]);
}
cout << "Finish setup socket connections to SPDZ engines." << endl;
// Run the commputation
send_private_inputs({salary_value}, sockets, nparties);
cout << "Sent private inputs to each SPDZ engine, waiting for result..." << endl;
int type = specification.get<int>();
switch (type)
{
case 'p':
{
gfp::init_field(specification.get<bigint>());
cerr << "using prime " << gfp::pr() << endl;
run<gfp>(salary_value, sockets, nparties);
break;
}
case 'R':
{
int R = specification.get<int>();
switch (R)
{
case 64:
run<Z2<64>>(salary_value, sockets, nparties);
break;
case 104:
run<Z2<104>>(salary_value, sockets, nparties);
break;
case 128:
run<Z2<128>>(salary_value, sockets, nparties);
break;
default:
cerr << R << "-bit ring not implemented";
exit(1);
}
break;
}
default:
cerr << "Type " << type << " not implemented";
exit(1);
}
// Get the result back (client_id of winning client)
gfp result = receive_result(sockets, nparties);
cout << "Winning client id is : " << result << endl;
for (unsigned int i = 0; i < sockets.size(); i++)
close_client_socket(sockets[i]);
for (int i = 0; i < nparties; i++)
delete sockets[i];
return 0;
}

View File

@@ -1,407 +0,0 @@
/*
* Demonstrate external client inputing and receiving outputs from a SPDZ process,
* following the protocol described in https://eprint.iacr.org/2015/1006.pdf.
* Uses SPDZ implemented encryption for external client communication, see bankers-bonus-client.cpp
* for a simpler client with no crypto.
*
* Provides a client to bankers_bonus_commsec.mpc program to calculate which banker pays for lunch based on
* the private value annual bonus. Up to 8 clients can connect to the SPDZ engines running
* the bankers_bonus.mpc program.
*
* Each connecting client:
* - sends an increasing id to identify the client, starting with 0
* - sends an integer (0 meaining more players will join this round or 1 meaning stop the round and calc the result).
* - runs crypto setup to demonstrate both DH Auth Encryption and STS protocol for comms security.
* - sends an integer input (bonus value to compare)
*
* The result is returned authenticated with a share of a random value:
* - share of winning unique id [y]
* - share of random value [r]
* - share of winning unique id * random value [w]
* winning unique id is valid if ∑ [y] * ∑ [r] = ∑ [w]
*
* To run with 2 parties (SPDZ engines) and 3 external clients:
* ./Scripts/setup-online.sh to create triple shares for each party (spdz engine).
* ./client-setup.x 2 -nc 3 to create the crypto key material for both parties and clients.
* ./compile.py bankers_bonus_commsec
* ./Scripts/run-online.sh bankers_bonus_commsec to run the engines.
*
* ./bankers-bonus-commsec-client.x 0 2 100 0
* ./bankers-bonus-commsec-client.x 1 2 200 0
* ./bankers-bonus-commsec-client.x 2 2 50 1
*
* Expect winner to be second client with id 1.
* Note here client id must match id used in generating client key material, Client-Keys-C<client id>.
*/
#include "Math/gfp.h"
#include "Math/gf2n.h"
#include "Networking/sockets.h"
#include "Networking/STS.h"
#include "Tools/int.h"
#include "Math/Setup.h"
#include "Protocols/fake-stuff.h"
#include <sodium.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
typedef pair< vector<octet>, vector<octet> > keypair_t; // A pair of send/recv keys for talking to SPDZ
typedef vector< keypair_t > commsec_t; // A database of send/recv keys indexed by server
typedef struct {
unsigned char client_secretkey[crypto_sign_SECRETKEYBYTES];
unsigned char client_publickey[crypto_sign_PUBLICKEYBYTES];
vector<int> client_publickey_ints;
vector< vector<unsigned char> >server_publickey;
} sign_key_container_t;
keypair_t sts_response_role_exceptions(sign_key_container_t keys, vector<int>& sockets, int server_id)
{
STS ke(&keys.server_publickey[server_id][0], keys.client_publickey, keys.client_secretkey);
sts_msg1_t m1;
sts_msg2_t m2;
sts_msg3_t m3;
octetStream os;
os.Receive(sockets[server_id]);
os.consume(m1.bytes, sizeof m1.bytes);
m2 = ke.recv_msg1(m1);
os.reset_write_head();
os.append(m2.pubkey, sizeof m2.pubkey);
os.append(m2.sig, sizeof m2.sig);
os.Send(sockets[server_id]);
os.Receive(sockets[server_id]);
os.consume(m3.bytes, sizeof m3.bytes);
ke.recv_msg3(m3);
vector<unsigned char> recvKey = ke.derive_secret(crypto_secretbox_KEYBYTES);
vector<unsigned char> sendKey = ke.derive_secret(crypto_secretbox_KEYBYTES);
return make_pair(sendKey,recvKey);
}
keypair_t sts_initiator_role_exceptions(sign_key_container_t keys, vector<int>& sockets, int server_id)
{
STS ke(&keys.server_publickey[server_id][0], keys.client_publickey, keys.client_secretkey);
sts_msg1_t m1;
sts_msg2_t m2;
sts_msg3_t m3;
octetStream os;
m1 = ke.send_msg1();
cout << "m1: ";
for (unsigned int j = 0; j < 32; j++)
cout << setfill('0') << setw(2) << hex << (int) m1.bytes[j];
cout << dec << endl;
os.reset_write_head();
os.append(m1.bytes, sizeof m1.bytes);
os.Send(sockets[server_id]);
os.reset_write_head();
os.Receive(sockets[server_id]);
os.consume(m2.pubkey, sizeof m2.pubkey);
os.consume(m2.sig, sizeof m2.sig);
m3 = ke.recv_msg2(m2);
os.reset_write_head();
os.append(m3.bytes, sizeof m3.bytes);
os.Send(sockets[server_id]);
vector<unsigned char> sendKey = ke.derive_secret(crypto_secretbox_KEYBYTES);
vector<unsigned char> recvKey = ke.derive_secret(crypto_secretbox_KEYBYTES);
return make_pair(sendKey,recvKey);
}
pair< vector<octet>, vector<octet> > sts_response_role(sign_key_container_t keys, vector<int>& sockets, int server_id)
{
pair< vector<octet>, vector<octet> > res;
try {
res = sts_response_role_exceptions(keys, sockets, server_id);
} catch(char const *e) {
cerr << "Error in STS: " << e << endl;
exit(1);
}
return res;
}
pair< vector<octet>, vector<octet> > sts_initiator_role(sign_key_container_t keys, vector<int>& sockets, int server_id)
{
pair< vector<octet>, vector<octet> > res;
try {
res = sts_initiator_role_exceptions(keys, sockets, server_id);
} catch(char const *e) {
cerr << "Error in STS: " << e << endl;
exit(1);
}
return res;
}
// Send the private inputs masked with a random value.
// Receive shares of a preprocessed triple from each SPDZ engine, combine and check the triples are valid.
// Add the private input value to triple[0] and send to each spdz engine.
void send_private_inputs(const vector<gfp>& values, vector<int>& sockets, int nparties,
commsec_t commsec, vector<octet*>& keys)
{
int num_inputs = values.size();
octetStream os;
vector< vector<gfp> > triples(num_inputs, vector<gfp>(3));
vector<gfp> triple_shares(3);
// Receive num_inputs triples from SPDZ
for (int j = 0; j < nparties; j++)
{
os.reset_write_head();
os.Receive(sockets[j]);
os.decrypt_sequence(&commsec[j].second[0],0);
os.decrypt(keys[j]);
for (int j = 0; j < num_inputs; j++)
{
for (int k = 0; k < 3; k++)
{
triple_shares[k].unpack(os);
triples[j][k] += triple_shares[k];
}
}
}
// Check triple relations
for (int i = 0; i < num_inputs; i++)
{
if (triples[i][0] * triples[i][1] != triples[i][2])
{
cerr << "Incorrect triple at " << i << ", aborting\n";
exit(1);
}
}
// Send inputs + triple[0], so SPDZ can compute shares of each value
os.reset_write_head();
for (int i = 0; i < num_inputs; i++)
{
gfp y = values[i] + triples[i][0];
y.pack(os);
}
for (int j = 0; j < nparties; j++)
{
octetStream temp = os;
temp.encrypt_sequence(&commsec[j].first[0], 0);
temp.Send(sockets[j]);
}
}
// Send public key in clear to each SPDZ engine.
void send_public_key(vector<int>& pubkey, int socket)
{
octetStream os;
os.reset_write_head();
for (unsigned int i = 0; i < pubkey.size(); i++)
{
os.store(pubkey[i]);
}
os.Send(socket);
}
// Assumes that Scripts/setup-online.sh has been run to compute prime
void initialise_fields(const string& dir_prefix)
{
int lg2;
bigint p;
string filename = dir_prefix + "Params-Data";
cout << "loading params from: " << filename << endl;
ifstream inpf(filename.c_str());
if (inpf.fail()) { throw file_error(filename.c_str()); }
inpf >> p;
inpf >> lg2;
inpf.close();
gfp::init_field(p);
gf2n::init_field(lg2);
}
// Assumes that client-setup has been run to create key pairs for clients and parties
void generate_symmetric_keys(vector<octet*>& keys, vector<int>& client_public_key_ints,
sign_key_container_t *sts_key, const string& dir_prefix, int client_no)
{
unsigned char client_publickey[crypto_box_PUBLICKEYBYTES];
unsigned char client_secretkey[crypto_box_SECRETKEYBYTES];
unsigned char server_publickey[crypto_box_PUBLICKEYBYTES];
unsigned char scalarmult_q[crypto_scalarmult_BYTES];
crypto_generichash_state h;
// read client public/secret keys + SPDZ server public keys
ifstream keyfile;
stringstream client_filename;
client_filename << dir_prefix << "Client-Keys-C" << client_no;
keyfile.open(client_filename.str().c_str());
if (keyfile.fail())
throw file_error(client_filename.str());
keyfile.read((char*)client_publickey, sizeof client_publickey);
if (keyfile.eof())
throw end_of_file(client_filename.str(), "client public key" );
// Convert client public key unsigned char to int, reverse endianness
for(unsigned int j = 0; j < client_public_key_ints.size(); j++) {
int keybyte = 0;
for(unsigned int k = 0; k < 4; k++) {
keybyte = keybyte + (((int)client_publickey[j*4+k]) << ((3-k) * 8));
}
client_public_key_ints[j] = keybyte;
}
keyfile.read((char*)client_secretkey, sizeof client_secretkey);
if (keyfile.eof()) {
throw end_of_file(client_filename.str(), "client private key" );
}
keyfile.read((char*)sts_key->client_publickey, crypto_sign_PUBLICKEYBYTES);
keyfile.read((char*)sts_key->client_secretkey, crypto_sign_SECRETKEYBYTES);
// Convert client public key unsigned char to int, reverse endianness
sts_key->client_publickey_ints.resize(8);
for(unsigned int j = 0; j < sts_key->client_publickey_ints.size(); j++) {
int keybyte = 0;
for(unsigned int k = 0; k < 4; k++) {
keybyte = keybyte + (((int)sts_key->client_publickey[j*4+k]) << ((3-k) * 8));
}
sts_key->client_publickey_ints[j] = keybyte;
}
for (unsigned int i = 0; i < keys.size(); i++)
{
keys[i] = new octet[crypto_generichash_BYTES];
keyfile.read((char*)server_publickey, crypto_box_PUBLICKEYBYTES);
if (keyfile.eof())
throw end_of_file(client_filename.str(), "server public key for party " + to_string(i));
keyfile.read((char*)(&sts_key->server_publickey[i][0]), crypto_sign_PUBLICKEYBYTES);
if (keyfile.eof())
throw end_of_file(client_filename.str(), "server public signing key for party " + to_string(i));
// Derive a shared key from this server's secret key and the client's public key
// shared key = h(q || client_secretkey || server_publickey)
if (crypto_scalarmult(scalarmult_q, client_secretkey, server_publickey) != 0) {
cerr << "Scalar mult failed\n";
exit(1);
}
crypto_generichash_init(&h, NULL, 0U, crypto_generichash_BYTES);
crypto_generichash_update(&h, scalarmult_q, sizeof scalarmult_q);
crypto_generichash_update(&h, client_publickey, sizeof client_publickey);
crypto_generichash_update(&h, server_publickey, sizeof server_publickey);
crypto_generichash_final(&h, keys[i], crypto_generichash_BYTES);
}
keyfile.close();
cout << "My public key is: ";
for (unsigned int j = 0; j < 32; j++)
cout << setfill('0') << setw(2) << hex << (int) client_publickey[j];
cout << dec << endl;
}
// Receive shares of the result and sum together.
// Also receive authenticating values.
gfp receive_result(vector<int>& sockets, int nparties, commsec_t commsec, vector<octet*>& keys)
{
vector<gfp> output_values(3);
octetStream os;
for (int i = 0; i < nparties; i++)
{
os.reset_write_head();
os.Receive(sockets[i]);
os.decrypt_sequence(&commsec[i].second[0],1);
os.decrypt(keys[i]);
for (unsigned int j = 0; j < 3; j++)
{
gfp value;
value.unpack(os);
output_values[j] += value;
}
}
if (output_values[0] * output_values[1] != output_values[2])
{
cerr << "Unable to authenticate output value as correct, aborting." << endl;
exit(1);
}
return output_values[0];
}
int main(int argc, char** argv)
{
int my_client_id;
int nparties;
int salary_value;
int finish;
int port_base = 14000;
sign_key_container_t sts_key;
string host_name = "localhost";
if (argc < 5) {
cout << "Usage is external-client <client identifier> <number of spdz parties> "
<< "<salary to compare> <finish (0 false, 1 true)> <optional host name, default localhost> "
<< "<optional spdz party port base number, default 14000>" << endl;
exit(0);
}
my_client_id = atoi(argv[1]);
nparties = atoi(argv[2]);
salary_value = atoi(argv[3]);
finish = atoi(argv[4]);
if (argc > 5)
host_name = argv[5];
if (argc > 6)
port_base = atoi(argv[6]);
sts_key.server_publickey.resize(nparties);
for(int i = 0 ; i < nparties; i++) {
sts_key.server_publickey[i].resize(crypto_sign_PUBLICKEYBYTES);
}
// init static gfp
string prep_data_prefix = get_prep_dir(nparties, 128, gf2n::default_degree());
initialise_fields(prep_data_prefix);
bigint::init_thread();
// Generate session keys to decrypt data sent from each spdz engine (party)
vector<octet*> session_keys(nparties);
vector<int> client_public_key_ints(8);
generate_symmetric_keys(session_keys, client_public_key_ints, &sts_key, prep_data_prefix, my_client_id);
// Setup connections from this client to each party socket and send the client public keys
vector<int> sockets(nparties);
// vector< pair <vector<octet>, vector <octet> > > commseckey(nparties);
commsec_t commseckey(nparties);
for (int i = 0; i < nparties; i++)
{
set_up_client_socket(sockets[i], host_name.c_str(), port_base + i);
send(sockets[i], (octet*) &my_client_id, sizeof(int));
octetStream os;
os.store(finish);
os.Send(sockets[i]);
send_public_key(sts_key.client_publickey_ints, sockets[i]);
send_public_key(client_public_key_ints, sockets[i]);
commseckey[i] = sts_initiator_role(sts_key, sockets, i);
}
cout << "Finish setup socket connections to SPDZ engines." << endl;
// Send the inputs to the SPDZ Engines
send_private_inputs({salary_value}, sockets, nparties, commseckey, session_keys);
cout << "Sent private inputs to each SPDZ engine, waiting for result..." << endl;
// Get the result back
gfp result = receive_result(sockets, nparties, commseckey, session_keys);
cout << "Winning client id is : " << result << endl;
for (unsigned int i = 0; i < sockets.size(); i++)
close_client_socket(sockets[i]);
return 0;
}