Low-Level Interface

In the following we will explain the basics of the C++ interface by walking trough Utils/paper-example.cpp.

template<class T>
void run(char** argv, int prime_length);

MP-SPDZ heavily uses templating to allow to reuse code between different protocols. run() is a simple example of this. The entire virtual machine in the Processor directory is built on the same principle. The central type is a type representing a share in a particular type.

// bit length of prime
const int prime_length = 128;

// compute number of 64-bit words needed
const int n_limbs = (prime_length + 63) / 64;

Computation modulo a prime requires to fix the number of limbs (64-bit words) at compile time. This allows for optimal memory usage and computation.

if (protocol == "MASCOT")
    run<Share<gfp_<0, n_limbs>>>(argv, prime_length);
else if (protocol == "CowGear")
    run<CowGearShare<gfp_<0, n_limbs>>>(argv, prime_length);

Share types for computation module a prime (and in \(\mathrm{GF}(2^n)\)) generally take one parameter for the computation domain. gfp_ in turn takes two parameters, a counter and the number of limbs. The counter allows to use several instances with different parameters. It can be chosen freely, but the convention is to use 0 for the online phase and 1 for the offline phase where required.

else if (protocol == "SPDZ2k")
    run<Spdz2kShare<64, 64>>(argv, 0);

Share types for computation modulo a power of two simply take the exponent as parameter, and some take an additional security parameter.

int my_number = atoi(argv[1]);
int n_parties = atoi(argv[2]);
int port_base = 9999;
Names N(my_number, n_parties, "localhost", port_base);

All implemented protocols require point-to-point connections between all parties. Names objects represent a setup of hostnames and IPs used to set up the actual connections. The chosen initialization provides a way where every party connects to party 0 on a specified location (localhost in this case), which then broadcasts the locations of all parties. The base port number is used to derive the port numbers for the parties to listen on (base + party number). See the the Names class for other possibilities such as a text file containing hostname and port number for each party.

CryptoPlayer P(N);

The networking setup is used to set up the actual connections. CryptoPlayer uses encrypted connection while PlainPlayer does not. If you use several instances (for several threads for example), you must use an integer identifier as the second parameter, which must differ from any other by at least the number of parties.

ProtocolSetup<T> setup(P, prime_length);

We have to use a specific prime for computation modulo a prime. This deterministically generates one of the desired length if necessary. For computation modulo a power of two, this does not do anything. Some protocols use an information-theoretic tag that is constant throughout the protocol. This code reads it from storage if available or generates a fresh one otherwise.

ProtocolSet<T> set(P, setup);
auto& input = set.input;
auto& protocol = set.protocol;
auto& output = set.output;

The ProtocolSet contains one instance for every essential protocol step.

int n = 1000;
vector<T> a(n), b(n);
T c;
typename T::clear result;

Remember that T stands for a share in the protocol. The derived type T::clear stands for the cleartext domain. Share types support linear operations such as addition, subtraction, and multiplication with a constant. Use T::constant() to convert a constant to a share type.

input.reset_all(P);
for (int i = 0; i < n; i++)
    input.add_from_all(i);
input.exchange();
for (int i = 0; i < n; i++)
{
    a[i] = input.finalize(0);
    b[i] = input.finalize(1);
}

The interface for all protocols proceeds in four stages:

  1. Initialization. This is required to initialize and reset data structures in consecutive use.

  2. Local data preparation

  3. Communication

  4. Output extraction

This blueprint allows for a minimal number of communication rounds.

protocol.init_dotprod(&processor);
for (int i = 0; i < n; i++)
    protocol.prepare_dotprod(a[i], b[i]);
protocol.next_dotprod();
protocol.exchange();
c = protocol.finalize_dotprod(n);

The initialization of the multiplication sets the preprocessing and output instances to use in Beaver multiplication. next_dotprod() separates dot products in the data preparation phase.

set.check();

Some protocols require a check of all multiplications up to a certain point. To guarantee that outputs do not reveal secret information, it has to be run before using the output protocol.

output.init_open(P);
output.prepare_open(c);
output.exchange(P);
result = output.finalize_open();

cout << "result: " << result << endl;
output.Check(P);

The output protocol follows the same blueprint as the multiplication protocol.

set.check();

Some output protocols require an additional to guarantee the correctness of outputs.

Thread Safety

The low-level interface generally isn’t thread-safe. In particular, you should only use one instance of ProtocolSetup in the whole program, and you should use only one instance of CryptoPlayer/PlainPlayer and ProtocolSet per thread.

Domain Types

gfp_<X, L>

Computation modulo a prime. L is the number of 64-bit limbs, that is, it covers primes of bit length \(64(L-1)+1\) to \(64L\). The type has to be initialized using init_field() or init_default(). The latter picks a prime given a bit length.

SignedZ2<K> / Z2<K>

Computation modulo \(2^K\). This is not a field.

gf2n_short / gf2n_long / gf2n_<T>

\(GF(2^n)\). T denotes a type that is used to store the values. It must support a variety of integer operations. The type has to be initialized using init_field(). The choice of degrees is limited. At the time of writing, 4, 8, 28, 40, 63, and 128 are supported if the storage type is large enough.

Share Types

Type

Protocol

AtlasShare<T>

Semi-honest version of ATLAS (Section 4.2). T must represent a field.

ChaiGearShare<T>

HighGear with covert key setup. T must be gfp_<X, L> or gf2n_short.

CowGearShare<T>

LowGear with covert key setup. T must be gfp_<X, L> or gf2n_short.

HemiShare<T>

Semi-honest protocol with Beaver multiplication based on semi-homomorphic encryption. T must be gfp_<X, L> or gf2n_short.

HighGearShare<T>

HighGear. T must be gfp_<X, L> or gf2n_short.

LowGearShare<T>

LowGear. T must be gfp_<X, L> or gf2n_short.

MaliciousShamirShare<T>

Shamir secret sharing with Beaver multiplication and sacrifice. T must represent a field.

MamaShare<T, N>

MASCOT with multiple MACs. T must represent a field, N is the number of MACs.

PostSacriRepFieldShare<T>

Post-sacrifice protocol using three-party replicated secret sharing with T representing a field.

PostSacriRepRingShare<K, S>

Post-sacrifice protocol using replicated three-party secret sharing modulo \(2^K\) with security parameter S.

Rep3Share2<K>

Three-party semi-honest protocol using replicated secret sharing modulo \(2^K\).

Rep4Share<T>

Four-party malicious protocol using replicated secret sharing over a field.

Rep4Share2<K>

Four-party malicious protocol using replicated secret sharing modulo \(2^K\).

SemiShare2<K>

Semi-honest dishonest-majority protocol using Beaver multiplication based on oblivious transfer modulo \(2^K\).

SemiShare<T>

Semi-honest dishonest-majority protocol using Beaver multiplication based on oblivious transfer in a field.

ShamirShare<T>

Semi-honest protocol based on Shamir’s secret sharing. T must represent a field.

Share<T>

MASCOT. T must represent a field.

SohoShare<T>

Semi-honest protocol with Beaver multiplication based on somewhat homomorphic encryption. T must be gfp_<X, L> or gf2n_short.

Spdz2kShare<K, S>

SPDZ2k computing modulo \(2^K\) with security parameter S.

SpdzWiseShare<K, S>

SPDZ-wise computing modulo \(2^K\) with security parameter S.

SpdzWiseShare<T>

SPDZ-wise. T must be MaliciousShamirShare or MaliciousRep3Share.

TemiShare<T>

Semi-honest protocol with Beaver multiplication based on threshold semi-homomorphic encryption. T must be gfp_<X, L> or gf2n_short.

Protocol Setup

template<class T>
class ProtocolSetup

Global setup for an arithmetic share type

Subclassed by MixedProtocolSetup< T >

Public Functions

inline ProtocolSetup(Player &P, int prime_length = 0, string directory = "")
Parameters
  • P – communication instance (used for MAC generation if needed)

  • prime_length – length of prime if computing modulo a prime

  • directory – location to read MAC if needed

inline ProtocolSetup(bigint prime, Player &P, string directory = "")
Parameters
  • prime – modulus for computation

  • P – communication instance (used for MAC generation if needed)

  • directory – location to read MAC if needed

Public Static Functions

static inline void set_batch_size(size_t batch_size)

Set how much preprocessing is produced at once.

template<class T>
class ProtocolSet

Input, multiplication, and output protocol instance for an arithmetic share type

Public Functions

inline ProtocolSet(Player &P, const ProtocolSetup<T> &setup)
Parameters
  • P – communication instance

  • setup – one-time setup instance

inline void check()

Run all protocol checks

template<class T>
class BinaryProtocolSetup

Global setup for a binary share type

Public Functions

inline BinaryProtocolSetup(Player &P, string directory = "")
Parameters
  • P – communication instance (used for MAC generation if needed)

  • directory – location to read MAC if needed

template<class T>
class BinaryProtocolSet

Input, multiplication, and output protocol instance for a binary share type

Public Functions

inline BinaryProtocolSet(Player &P, const BinaryProtocolSetup<T> &setup)
Parameters
  • P – communication instance

  • setup – one-time setup instance

inline void check()

Run all protocol checks

template<class T>
class MixedProtocolSetup : public ProtocolSetup<T>

Global setup for an arithmetic share type and the corresponding binary one

Public Functions

inline MixedProtocolSetup(Player &P, int prime_length = 0, string directory = "")
Parameters
  • P – communication instance (used for MAC generation if needed)

  • prime_length – length of prime if computing modulo a prime

  • directory – location to read MAC if needed

template<class T>
class MixedProtocolSet

Input, multiplication, and output protocol instance for an arithmetic share type and the corresponding binary one

Public Functions

inline MixedProtocolSet(Player &P, const MixedProtocolSetup<T> &setup)
Parameters
  • P – communication instance

  • setup – one-time setup instance

inline void check()

Run all protocol checks

Protocol Interfaces

template<class T>
class ProtocolBase

Abstract base class for multiplication protocols

Subclassed by Replicated< T >

Public Functions

T mul(const T &x, const T &y)

Single multiplication.

inline virtual void init(Preprocessing<T>&, typename T::MAC_Check&)

Initialize protocol if needed (repeated call possible)

virtual void init_mul() = 0

Initialize multiplication round.

virtual void prepare_mul(const T &x, const T &y, int n = -1) = 0

Schedule multiplication of operand pair.

virtual void exchange() = 0

Run multiplication protocol.

virtual T finalize_mul(int n = -1) = 0

Get next multiplication result.

virtual void finalize_mult(T &res, int n = -1)

Store next multiplication result in res

inline void init_dotprod()

Initialize dot product round.

inline void prepare_dotprod(const T &x, const T &y)

Add operand pair to current dot product.

inline void next_dotprod()

Finish dot product.

T finalize_dotprod(int length)

Get next dot product result.

template<class T>
class InputBase

Abstract base for input protocols

Subclassed by Input< T >

Public Functions

virtual void reset(int player) = 0

Initialize input round for player

void reset_all(PlayerBase &P)

Initialize input round for all players.

virtual void add_mine(const typename T::open_type &input, int n_bits = -1) = 0

Schedule input from me.

virtual void add_other(int player, int n_bits = -1) = 0

Schedule input from other player.

void add_from_all(const typename T::open_type &input, int n_bits = -1)

Schedule input from all players.

virtual void exchange()

Run input protocol for all players.

virtual T finalize(int player, int n_bits = -1)

Get share for next input from player

template<class T>
class MAC_Check_Base

Abstract base class for opening protocols

Public Functions

inline virtual void Check(const Player &P)

Run checking protocol.

inline const T::mac_key_type::Scalar &get_alphai() const

Get MAC key.

virtual void POpen(vector<typename T::open_type> &values, const vector<T> &S, const Player &P)

Open values in S and store results in values

inline T::open_type open(const T &secret, const Player &P)

Open single value.

virtual void init_open(const Player &P, int n = 0)

Initialize opening round.

virtual void prepare_open(const T &secret, int n_bits = -1)

Add value to be opened.

virtual void exchange(const Player &P) = 0

Run opening protocol.

virtual T::clear finalize_open()

Get next opened value.

virtual void CheckFor(const typename T::open_type &value, const vector<T> &shares, const Player &P)

Check whether all shares are value

template<class T>
class Preprocessing : public PrepBase

Abstract base class for preprocessing

Subclassed by BufferPrep< T >, Sub_Data_Files< T >

Public Functions

virtual array<T, 3> get_triple(int n_bits)

Get fresh random multiplication triple.

virtual T get_bit()

Get fresh random bit.

virtual T get_random()

Get fresh random value in domain.

virtual void get_dabit(T &a, typename T::bit_type &b)

Store fresh daBit in a (arithmetic part) and b (binary part)

inline virtual edabitvec<T> get_edabitvec(bool, int)

Get fresh edaBit chunk.

template<class T>
class BufferPrep : public Preprocessing<T>

Abstract base class for live preprocessing

Subclassed by BitPrep< T >

Public Functions

virtual edabitvec<T> get_edabitvec(bool strict, int n_bits)

Get fresh edaBit chunk.

virtual T get_random()

Get fresh random value.

Public Static Functions

static inline void basic_setup(Player &P)

Key-independent setup if necessary (cryptosystem parameters)

static inline void setup(Player &P, typename T::mac_key_type alphai)

Generate keys if necessary.

static inline void teardown()

Free memory of global cryptosystem parameters.

Domain Reference

template<int X, int L>
class gfp_ : public ValueInterface

Type for values in a field defined by integers modulo a prime in a specific range for fixed storage. It supports basic arithmetic operations and bit-wise operations. The latter use the canonical representation in the range [0, p-1]. X is a counter to allow several moduli being used at the same time. L is the number of 64-bit limbs, that is, the prime has to have bit length in [64*L-63, 64*L]. See gfpvar_ for a more flexible alternative. Convert to bigint to access the canonical integer representation.

Public Functions

inline gfp_()

Initialize to zero.

inline gfp_(const mpz_class &x)

Convert from integer without range restrictions.

template<int Y>
gfp_(const gfp_<Y, L> &x)

Convert from different domain via canonical integer representation.

gfp_ sqrRoot()

Deterministic square root.

inline void randomize(PRNG &G, int n = -1)

Sample with uniform distribution.

Parameters
  • G – randomness generator

  • n – (unused)

inline void pack(octetStream &o, int n = -1) const

Append to buffer in native format.

Parameters
  • o – buffer

  • n – (unused)

inline void unpack(octetStream &o, int n = -1)

Read from buffer in native format

Parameters
  • o – buffer

  • n – (unused)

Public Static Functions

static void init_field(const bigint &p, bool mont = true)

Initialize the field.

Parameters
  • p – prime modulus

  • mont – whether to use Montgomery representation

static void init_default(int lgp, bool mont = true)

Initialize the field to a prime of a given bit length.

Parameters
  • lgp – bit length

  • mont – whether to use Montgomery representation

static inline const bigint &pr()

Get the prime modulus

Friends

inline friend ostream &operator<<(ostream &s, const gfp_ &x)

Human-readable output in the range [-p/2, p/2].

Parameters
  • s – output stream

  • x – value

inline friend istream &operator>>(istream &s, gfp_ &x)

Human-readable input without range restrictions

Parameters
  • s – input stream

  • x – value

template<int X, int L>
class gfpvar_

Type for values in a field defined by integers modulo a prime up to a certain length for fixed storage. X is a counter to allow several moduli being used at the same time. L is the maximum number of 64-bit limbs, that is, the prime has to have bit length at most 64*L. The interface replicates gfp_.

template<int K>
class Z2 : public ValueInterface

Type for values in the ring defined by the integers modulo 2^K representing [0, 2^K-1]. It supports arithmetic, bit-wise, and output streaming operations. It does not need initialization because K completely defines the domain.

Subclassed by SignedZ2< K >

Public Functions

inline Z2()

Initialize to zero.

Z2(const bigint &x)

Convert from unrestricted integer.

template<int L>
inline Z2(const Z2<L> &x)

Convert from different domain via the canonical integer representation.

inline mp_limb_t get_limb(int i) const

Get 64-bit part.

Parameters

i – return word containing 64*i- to 64*i+63-least significant bits

Z2 sqrRoot()

Deterministic square root for values with least significate bit 1. Raises an exception otherwise.

void randomize(PRNG &G, int n = -1)

Sample with uniform distribution.

Parameters
  • G – randomness generator

  • n – (unused)

void pack(octetStream &o, int = -1) const

Append to buffer in native format.

Parameters
  • o – buffer

  • n – (unused)

void unpack(octetStream &o, int n = -1)

Read from buffer in native format

Parameters
  • o – buffer

  • n – (unused)

template<int K>
class SignedZ2 : public Z2<K>

Type for values in the ring defined by the integers modulo 2^K representing [-2^(K-1), 2^(K-1)-1]. It supports arithmetic, bit-wise, comparison, and output streaming operations. It does not need initialization because K completely defines the domain.

Public Functions

inline SignedZ2()

Initialization to zero

template<int L>
inline SignedZ2(const SignedZ2<L> &other)

Conversion from another domain via the signed representation

The following is not used as a domain, but it helps using the above types, in particular gfp_<X, L> and gfpvar_<X, L>.

class bigint : public mpz_class

Type for arbitrarily large integers. This is a sub-class of mpz_class from GMP. As such, it implements all integers operations and input/output via C++ streams. In addition, the get_ui() member function allows retrieving the least significant 64 bits.

Public Functions

inline bigint()

Initialize to zero.

template<int X, int L>
bigint(const gfp_<X, L> &x)

Convert to canonical representation as non-negative number.

template<int X, int L>
bigint(const gfpvar_<X, L> &x)

Convert to canonical representation as non-negative number.

template<int K>
bigint(const Z2<K> &x)

Convert to canonical representation as non-negative number.

template<int K>
bigint(const SignedZ2<K> &x)

Convert to canonical representation as non-negative number.

template<int X, int L>
bigint &from_signed(const gfp_<X, L> &other)

Convert to signed representation in :math:[-p/2,p/2].