Optimized matrix multiplication; data type for quantization.

This commit is contained in:
Marcel Keller
2019-02-14 15:15:37 +11:00
parent 216fbdf1e1
commit b6a18675e8
108 changed files with 2676 additions and 999 deletions

1
.gitignore vendored
View File

@@ -62,6 +62,7 @@ Programs/Public-Input/*
*.a
*.static
*.d
local/
# Packages #
############

View File

@@ -466,3 +466,5 @@ template class MAC_Check_Base<ShamirShare<gfp>>;
template class MAC_Check_Base<ShamirShare<gf2n>>;
template class MAC_Check_Base<MaliciousShamirShare<gfp>>;
template class MAC_Check_Base<MaliciousShamirShare<gf2n>>;
template class MAC_Check_Base<Share<gfp>>;
template class MAC_Check_Base<Share<gf2n>>;

View File

@@ -85,14 +85,15 @@ void CommMaliciousRepMC<T>::POpen_Begin(vector<typename T::clear>& values,
for (auto& x : S)
for (int i = 0; i < 2; i++)
x[i].pack(os[1 - i]);
P.send_relative(os);
P.pass_around(os[0], 1);
P.pass_around(os[1], 2);
}
template<class T>
void CommMaliciousRepMC<T>::POpen_End(vector<typename T::clear>& values,
const vector<T>& S, const Player& P)
{
P.receive_relative(os);
(void) P;
if (os[0] != os[1])
throw mac_fail();
values.clear();

View File

@@ -4,7 +4,7 @@
*/
#include "MaliciousShamirMC.h"
#include "Processor/ShamirMachine.h"
#include "Machines/ShamirMachine.h"
template<class T>
MaliciousShamirMC<T>::MaliciousShamirMC()

View File

@@ -8,7 +8,7 @@
#include "MAC_Check.h"
#include "Math/ShamirShare.h"
#include "Processor/ShamirMachine.h"
#include "Machines/ShamirMachine.h"
template<class T>
class ShamirMC : public MAC_Check_Base<T>

View File

@@ -14,7 +14,12 @@ void AuthValue::assign(const word& value, const int128& mac_key, bool not_first_
share = 0;
else
share = value;
#ifdef __PCLMUL__
mac = _mm_clmulepi64_si128(_mm_cvtsi64_si128(mac_key.get_lower()), _mm_cvtsi64_si128(value), 0);
#else
(void) mac_key;
throw runtime_error("need to compile with PCLMUL support");
#endif
}
ostream& operator<<(ostream& o, const AuthValue& auth_value)

View File

@@ -12,6 +12,7 @@
#include <string.h>
#include "Tools/FlexBuffer.h"
#include "Math/gf2nlong.h"
using namespace std;
@@ -54,8 +55,7 @@ ostream& operator<<(ostream& o, const __m128i& x);
inline bool Key::operator==(const Key& other) {
__m128i neq = _mm_xor_si128(r, other.r);
return _mm_test_all_zeros(neq,neq);
return int128(r) == other.r;
}
inline Key& Key::operator-=(const Key& other) {
@@ -88,7 +88,14 @@ inline void Key::set_signal(bool signal)
inline Key Key::doubling(int i) const
{
#ifdef __AVX2__
return _mm_sllv_epi64(r, _mm_set_epi64x(i, i));
#else
uint64_t halfs[2];
halfs[1] = _mm_cvtsi128_si64(_mm_unpackhi_epi64(r, r)) << i;
halfs[0] = _mm_cvtsi128_si64(r) << i;
return _mm_loadu_si128((__m128i*)halfs);
#endif
}

View File

@@ -8,7 +8,7 @@
#include <mutex>
#include <boost/atomic.hpp>
#include <sys/sysinfo.h>
#include <boost/thread.hpp>
#include "Register.h"
#include "GarbledGate.h"
@@ -31,7 +31,7 @@ class BooleanCircuit;
#ifndef N_EVAL_THREADS
// Default Intel desktop processor has 8 half cores.
// This is beneficial if only one AES available per full core.
#define N_EVAL_THREADS (get_nprocs())
#define N_EVAL_THREADS (thread::hardware_concurrency())
#endif

View File

@@ -9,6 +9,8 @@
#include "GC/Instruction.hpp"
#include "GC/Program.hpp"
#include "Processor/Instruction.hpp"
namespace GC
{

View File

@@ -1,4 +1,5 @@
#include "aes.h"
#include <stdexcept>
#ifdef _WIN32
#include "StdAfx.h"
@@ -10,6 +11,7 @@ void AES_128_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
//block *kp = (block *)&aesKey;
aesKey->rd_key[0] = x0 = _mm_loadu_si128((block*)userkey);
x2 = _mm_setzero_si128();
#ifdef __AES__
EXPAND_ASSIST(x0, x1, x2, x0, 255, 1); aesKey->rd_key[1] = x0;
EXPAND_ASSIST(x0, x1, x2, x0, 255, 2); aesKey->rd_key[2] = x0;
EXPAND_ASSIST(x0, x1, x2, x0, 255, 4); aesKey->rd_key[3] = x0;
@@ -20,198 +22,8 @@ void AES_128_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
EXPAND_ASSIST(x0, x1, x2, x0, 255, 128); aesKey->rd_key[8] = x0;
EXPAND_ASSIST(x0, x1, x2, x0, 255, 27); aesKey->rd_key[9] = x0;
EXPAND_ASSIST(x0, x1, x2, x0, 255, 54); aesKey->rd_key[10] = x0;
}
void AES_192_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
{
__m128i x0,x1,x2,x3,tmp,*kp = (block *)&aesKey;
kp[0] = x0 = _mm_loadu_si128((block*)userkey);
tmp = x3 = _mm_loadu_si128((block*)(userkey+16));
x2 = _mm_setzero_si128();
EXPAND192_STEP(1,1);
EXPAND192_STEP(4,4);
EXPAND192_STEP(7,16);
EXPAND192_STEP(10,64);
}
void AES_256_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
{
__m128i x0, x1, x2, x3;/* , *kp = (block *)&aesKey;*/
aesKey->rd_key[0] = x0 = _mm_loadu_si128((block*)userkey);
aesKey->rd_key[1] = x3 = _mm_loadu_si128((block*)(userkey + 16));
x2 = _mm_setzero_si128();
EXPAND_ASSIST(x0, x1, x2, x3, 255, 1); aesKey->rd_key[2] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 1); aesKey->rd_key[3] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 2); aesKey->rd_key[4] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 2); aesKey->rd_key[5] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 4); aesKey->rd_key[6] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 4); aesKey->rd_key[7] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 8); aesKey->rd_key[8] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 8); aesKey->rd_key[9] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 16); aesKey->rd_key[10] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 16); aesKey->rd_key[11] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 32); aesKey->rd_key[12] = x0;
EXPAND_ASSIST(x3, x1, x2, x0, 170, 32); aesKey->rd_key[13] = x3;
EXPAND_ASSIST(x0, x1, x2, x3, 255, 64); aesKey->rd_key[14] = x0;
}
void AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *aesKey)
{
if (bits == 128) {
AES_128_Key_Expansion(userKey, aesKey);
} else if (bits == 192) {
AES_192_Key_Expansion(userKey, aesKey);
} else if (bits == 256) {
AES_256_Key_Expansion(userKey, aesKey);
}
aesKey->rounds = 6 + bits / 32;
}
void AES_encryptC(block *in, block *out, AES_KEY *aesKey)
{
int j, rnds = ROUNDS(aesKey);
const __m128i *sched = ((__m128i *)(aesKey->rd_key));
__m128i tmp = _mm_load_si128((__m128i*)in);
tmp = _mm_xor_si128(tmp, sched[0]);
for (j = 1; j<rnds; j++) tmp = _mm_aesenc_si128(tmp, sched[j]);
tmp = _mm_aesenclast_si128(tmp, sched[j]);
_mm_store_si128((__m128i*)out, tmp);
}
void AES_ecb_encrypt(block *blk, AES_KEY *aesKey) {
unsigned j, rnds = ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
*blk = _mm_xor_si128(*blk, sched[0]);
for (j = 1; j<rnds; ++j)
*blk = _mm_aesenc_si128(*blk, sched[j]);
*blk = _mm_aesenclast_si128(*blk, sched[j]);
}
void AES_ecb_encrypt_blks(block *blks, unsigned nblks, AES_KEY *aesKey) {
unsigned i,j,rnds=ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
for (i=0; i<nblks; ++i)
blks[i] =_mm_xor_si128(blks[i], sched[0]);
for(j=1; j<rnds; ++j)
for (i=0; i<nblks; ++i)
blks[i] = _mm_aesenc_si128(blks[i], sched[j]);
for (i=0; i<nblks; ++i)
blks[i] =_mm_aesenclast_si128(blks[i], sched[j]);
}
void AES_ecb_encrypt_blks_4(block *blks, AES_KEY *aesKey) {
unsigned j, rnds = ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
blks[0] = _mm_xor_si128(blks[0], sched[0]);
blks[1] = _mm_xor_si128(blks[1], sched[0]);
blks[2] = _mm_xor_si128(blks[2], sched[0]);
blks[3] = _mm_xor_si128(blks[3], sched[0]);
for (j = 1; j < rnds; ++j){
blks[0] = _mm_aesenc_si128(blks[0], sched[j]);
blks[1] = _mm_aesenc_si128(blks[1], sched[j]);
blks[2] = _mm_aesenc_si128(blks[2], sched[j]);
blks[3] = _mm_aesenc_si128(blks[3], sched[j]);
}
blks[0] = _mm_aesenclast_si128(blks[0], sched[j]);
blks[1] = _mm_aesenclast_si128(blks[1], sched[j]);
blks[2] = _mm_aesenclast_si128(blks[2], sched[j]);
blks[3] = _mm_aesenclast_si128(blks[3], sched[j]);
}
void AES_ecb_encrypt_blks_2_in_out(block *in, block *out, AES_KEY *aesKey) {
unsigned j, rnds = ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
out[0] = _mm_xor_si128(in[0], sched[0]);
out[1] = _mm_xor_si128(in[1], sched[0]);
for (j = 1; j < rnds; ++j){
out[0] = _mm_aesenc_si128(out[0], sched[j]);
out[1] = _mm_aesenc_si128(out[1], sched[j]);
}
out[0] = _mm_aesenclast_si128(out[0], sched[j]);
out[1] = _mm_aesenclast_si128(out[1], sched[j]);
}
void AES_ecb_encrypt_blks_4_in_out(block *in, block *out, AES_KEY *aesKey) {
unsigned j, rnds = ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
//block temp[4];
out[0] = _mm_xor_si128(in[0], sched[0]);
out[1] = _mm_xor_si128(in[1], sched[0]);
out[2] = _mm_xor_si128(in[2], sched[0]);
out[3] = _mm_xor_si128(in[3], sched[0]);
for (j = 1; j < rnds; ++j){
out[0] = _mm_aesenc_si128(out[0], sched[j]);
out[1] = _mm_aesenc_si128(out[1], sched[j]);
out[2] = _mm_aesenc_si128(out[2], sched[j]);
out[3] = _mm_aesenc_si128(out[3], sched[j]);
}
out[0] = _mm_aesenclast_si128(out[0], sched[j]);
out[1] = _mm_aesenclast_si128(out[1], sched[j]);
out[2] = _mm_aesenclast_si128(out[2], sched[j]);
out[3] = _mm_aesenclast_si128(out[3], sched[j]);
}
void AES_ecb_encrypt_chunk_in_out(block *in, block *out, unsigned nblks, AES_KEY *aesKey) {
int numberOfLoops = nblks / 8;
int blocksPipeLined = numberOfLoops * 8;
int remainingEncrypts = nblks - blocksPipeLined;
unsigned j, rnds = ROUNDS(aesKey);
const block *sched = ((block *)(aesKey->rd_key));
for (int i = 0; i < numberOfLoops; i++){
out[0 + i * 8] = _mm_xor_si128(in[0 + i * 8], sched[0]);
out[1 + i * 8] = _mm_xor_si128(in[1 + i * 8], sched[0]);
out[2 + i * 8] = _mm_xor_si128(in[2 + i * 8], sched[0]);
out[3 + i * 8] = _mm_xor_si128(in[3 + i * 8], sched[0]);
out[4 + i * 8] = _mm_xor_si128(in[4 + i * 8], sched[0]);
out[5 + i * 8] = _mm_xor_si128(in[5 + i * 8], sched[0]);
out[6 + i * 8] = _mm_xor_si128(in[6 + i * 8], sched[0]);
out[7 + i * 8] = _mm_xor_si128(in[7 + i * 8], sched[0]);
for (j = 1; j < rnds; ++j){
out[0 + i * 8] = _mm_aesenc_si128(out[0 + i * 8], sched[j]);
out[1 + i * 8] = _mm_aesenc_si128(out[1 + i * 8], sched[j]);
out[2 + i * 8] = _mm_aesenc_si128(out[2 + i * 8], sched[j]);
out[3 + i * 8] = _mm_aesenc_si128(out[3 + i * 8], sched[j]);
out[4 + i * 8] = _mm_aesenc_si128(out[4 + i * 8], sched[j]);
out[5 + i * 8] = _mm_aesenc_si128(out[5 + i * 8], sched[j]);
out[6 + i * 8] = _mm_aesenc_si128(out[6 + i * 8], sched[j]);
out[7 + i * 8] = _mm_aesenc_si128(out[7 + i * 8], sched[j]);
}
out[0 + i * 8] = _mm_aesenclast_si128(out[0 + i * 8], sched[j]);
out[1 + i * 8] = _mm_aesenclast_si128(out[1 + i * 8], sched[j]);
out[2 + i * 8] = _mm_aesenclast_si128(out[2 + i * 8], sched[j]);
out[3 + i * 8] = _mm_aesenclast_si128(out[3 + i * 8], sched[j]);
out[4 + i * 8] = _mm_aesenclast_si128(out[4 + i * 8], sched[j]);
out[5 + i * 8] = _mm_aesenclast_si128(out[5 + i * 8], sched[j]);
out[6 + i * 8] = _mm_aesenclast_si128(out[6 + i * 8], sched[j]);
out[7 + i * 8] = _mm_aesenclast_si128(out[7 + i * 8], sched[j]);
}
for (int i = blocksPipeLined; i < blocksPipeLined + remainingEncrypts; ++i){
out[i] = _mm_xor_si128(in[i], sched[0]);
for (j = 1; j < rnds; ++j)
{
out[i] = _mm_aesenc_si128(out[i], sched[j]);
}
out[i] = _mm_aesenclast_si128(out[i], sched[j]);
}
#else
(void) x1, (void) x2;
throw std::runtime_error("need to compile with AES-NI support");
#endif
}

View File

@@ -24,7 +24,6 @@
typedef struct { block rd_key[15]; int rounds; } AES_KEY;
#define ROUNDS(ctx) ((ctx)->rounds)
#define EXPAND_ASSIST(v1,v2,v3,v4,shuff_const,aes_const) \
v2 = _mm_aeskeygenassist_si128(v4,aes_const); \
@@ -37,36 +36,6 @@ typedef struct { block rd_key[15]; int rounds; } AES_KEY;
v2 = _mm_shuffle_epi32(v2,shuff_const); \
v1 = _mm_xor_si128(v1,v2)
#define EXPAND192_STEP(idx,aes_const) \
EXPAND_ASSIST(x0,x1,x2,x3,85,aes_const); \
x3 = _mm_xor_si128(x3,_mm_slli_si128 (x3, 4)); \
x3 = _mm_xor_si128(x3,_mm_shuffle_epi32(x0, 255)); \
kp[idx] = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(tmp), \
_mm_castsi128_ps(x0), 68)); \
kp[idx+1] = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), \
_mm_castsi128_ps(x3), 78)); \
EXPAND_ASSIST(x0,x1,x2,x3,85,(aes_const*2)); \
x3 = _mm_xor_si128(x3,_mm_slli_si128 (x3, 4)); \
x3 = _mm_xor_si128(x3,_mm_shuffle_epi32(x0, 255)); \
kp[idx+2] = x0; tmp = x3
void AES_128_Key_Expansion(const unsigned char *userkey, AES_KEY* aesKey);
void AES_192_Key_Expansion(const unsigned char *userkey, AES_KEY* aesKey);
void AES_256_Key_Expansion(const unsigned char *userkey, AES_KEY* aesKey);
void AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *aesKey);
void AES_encryptC(block *in, block *out, AES_KEY *aesKey);
void AES_ecb_encrypt(block *blk, AES_KEY *aesKey);
void AES_ecb_encrypt_blks(block *blks, unsigned nblks, AES_KEY *aesKey);
void AES_ecb_encrypt_blks_4(block *blk, AES_KEY *aesKey);
void AES_ecb_encrypt_blks_4_in_out(block *in, block *out, AES_KEY *aesKey);
void AES_ecb_encrypt_blks_2_in_out(block *in, block *out, AES_KEY *aesKey);
void AES_ecb_encrypt_chunk_in_out(block *in, block *out, unsigned nblks, AES_KEY *aesKey);
#endif /* PROTOCOL_INC_AES_H_ */

View File

@@ -36,7 +36,7 @@ Server::Server(int port, int expected_clients, ServerUpdatable* updatable, unsig
_servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
_servaddr.sin_port = htons(_port);
if( 0 != bind(_servfd, (struct sockaddr *) &_servaddr, sizeof(_servaddr)) )
if( 0 != ::bind(_servfd, (struct sockaddr *) &_servaddr, sizeof(_servaddr)) )
printf("Server:: Error binding to %d: \n%s\n", _port, strerror(errno));
if(0 != listen(_servfd, _expected_clients))

View File

@@ -1,21 +0,0 @@
/*
* prf.cpp
*
*/
#include "prf.h"
#include "aes.h"
#include "proto_utils.h"
void PRF_single(const Key& key, char* input, char* output)
{
// printf("prf_single\n");
// std::cout << *key;
// phex(input, 16);
AES_KEY aes_key;
AES_128_Key_Expansion((const unsigned char*)(&(key.r)), &aes_key);
aes_key.rounds=10;
AES_encryptC((block*)input, (block*)output, &aes_key);
// phex(output, 16);
}

View File

@@ -11,15 +11,6 @@
#include "Tools/aes.h"
void PRF_single(const Key& key, char* input, char* output);
inline Key PRF_single(const Key& key, const Key& input)
{
Key output;
PRF_single(key, (char*)&input, (char*)&output);
return output;
}
inline void PRF_chunk(const Key& key, char* input, char* output, int number)
{
__m128i* in = (__m128i*)input;

View File

@@ -1,5 +1,11 @@
The changelog explains changes pulled through from the private development repository. Bug fixes and small enchancements are committed between releases and not documented here.
## 0.0.7 (Feb 14, 2019)
- Simplified installation on macOS
- Optimized matrix multiplication
- Data type for quantization
## 0.0.6 (Jan 5, 2019)
- Shamir secret sharing

18
CONFIG
View File

@@ -4,6 +4,7 @@ OPTIM= -O3
#PROF = -pg
#DEBUG = -DDEBUG
#MEMPROTECT = -DMEMPROTECT
GDEBUG = -g
# set this to your preferred local storage directory
PREP_DIR = '-DPREP_DIR="Player-Data/"'
@@ -16,8 +17,15 @@ USE_NTL = 0
USE_GF2N_LONG = 1
# set to -march=<architecture> for optimization
# AVX2 support (Haswell or later) changes the bit matrix transpose
ARCH = -mtune=native -mavx
# AES-NI is required for BMR
# PCLMUL is required for GF(2^128) computation
# AVX2 support (Haswell or later) is used to optimize OT
# AVX/AVX2 is required for replicated binary secret sharing
# BMI2 is used to optimize multiplication modulo a prime
ARCH = -mtune=native -msse4.1 -maes -mpclmul -mavx -mavx2 -mbmi2
# allow to set compiler in CONFIG.mine
CXX = g++
#use CONFIG.mine to overwrite DIR settings
-include CONFIG.mine
@@ -30,7 +38,7 @@ endif
# Default is 2, which suffices for 128-bit p
# MOD = -DMAX_MOD_SZ=2
LDLIBS = -lmpirxx -lmpir -lsodium $(MY_LDLIBS) -lm -lpthread
LDLIBS = -lmpirxx -lmpir -lsodium $(MY_LDLIBS)
LDLIBS += -lboost_system -lssl -lcrypto
ifeq ($(USE_NTL),1)
@@ -44,8 +52,6 @@ endif
BOOST = -lboost_system -lboost_thread $(MY_BOOST)
CXX = g++ -no-pie
#CXX = clang++
CFLAGS += $(ARCH) $(MY_CFLAGS) -g -Wextra -Wall $(OPTIM) -I$(ROOT) -pthread $(PROF) $(DEBUG) $(MOD) $(MEMPROTECT) $(GF2N_LONG) $(PREP_DIR) -maes -mpclmul -msse4.1 -mavx -mavx2 -mbmi2 --std=c++11 -Werror
CFLAGS += $(ARCH) $(MY_CFLAGS) $(GDEBUG) -Wextra -Wall $(OPTIM) -I$(ROOT) -pthread $(PROF) $(DEBUG) $(MOD) $(MEMPROTECT) $(GF2N_LONG) $(PREP_DIR) -std=c++11 -Werror
CPPFLAGS = $(CFLAGS)
LD = $(CXX)

View File

@@ -14,6 +14,7 @@
#include "Processor/Data_Files.h"
#include "Auth/fake-stuff.hpp"
#include "Processor/Data_Files.hpp"
#include <sstream>
#include <fstream>

View File

@@ -6,11 +6,10 @@ from Compiler import util, oram, floatingpoint
import Compiler.GC.instructions as inst
import operator
class bits(Tape.Register):
class bits(Tape.Register, _structure):
n = 40
size = 1
PreOp = staticmethod(floatingpoint.PreOpN)
MemValue = staticmethod(lambda value: MemValue(value))
decomposed = None
@staticmethod
def PreOR(l):
@@ -72,7 +71,10 @@ class bits(Tape.Register):
def n_elements():
return 1
@classmethod
def load_mem(cls, address, mem_type=None):
def load_mem(cls, address, mem_type=None, size=None):
if size not in (None, 1):
v = [cls.load_mem(address + i) for i in range(size)]
return cls.vec(v)
res = cls()
if mem_type == 'sd':
return cls.load_dynamic_mem(address)
@@ -376,6 +378,9 @@ class sbits(bits):
class sbitvec(object):
@classmethod
def get_type(cls, n):
return cls
@classmethod
def from_vec(cls, vector):
res = cls()
res.v = list(vector)
@@ -419,6 +424,15 @@ class sbitvec(object):
@classmethod
def conv(cls, other):
return cls.from_vec(other.v)
@property
def size(self):
return self.v[0].n
def store_in_mem(self, address):
for i, x in enumerate(self.elements()):
x.store_in_mem(address + i)
def bit_decompose(self):
return self.v
bit_compose = from_vec
class bit(object):
n = 1
@@ -499,7 +513,9 @@ class sbitint(_bitint, _number, sbits):
bin_type = None
types = {}
@classmethod
def get_type(cls, n):
def get_type(cls, n, other=None):
if isinstance(other, sbitvec):
return sbitvec
if n in cls.types:
return cls.types[n]
sbits_type = sbits.get_type(n)
@@ -511,6 +527,12 @@ class sbitint(_bitint, _number, sbits):
cls.types[n] = _
return _
@classmethod
def combo_type(cls, other):
if isinstance(other, sbitintvec):
return sbitintvec
else:
return cls
@classmethod
def new(cls, value=None, n=None):
return cls.get_type(n)(value)
def set_length(*args):
@@ -523,7 +545,9 @@ class sbitint(_bitint, _number, sbits):
return super(sbitint, cls).bit_compose(bits)
def force_bit_decompose(self, n_bits=None):
return sbits.bit_decompose(self, n_bits)
def TruncMul(self, other, k, m, kappa=None):
def TruncMul(self, other, k, m, kappa=None, nearest=False):
if nearest:
raise CompilerError('round to nearest not implemented')
self_bits = self.bit_decompose()
other_bits = other.bit_decompose()
if len(self_bits) + len(other_bits) != k:
@@ -532,10 +556,12 @@ class sbitint(_bitint, _number, sbits):
(len(self_bits), len(other_bits), k))
t = self.get_type(k)
a = t.bit_compose(self_bits + [self_bits[-1]] * (k - len(self_bits)))
t = other.get_type(k)
b = t.bit_compose(other_bits + [other_bits[-1]] * (k - len(other_bits)))
product = a * b
res_bits = product.bit_decompose()[m:k]
return self.bit_compose(res_bits)
t = self.combo_type(other)
return t.bit_compose(res_bits)
def Norm(self, k, f, kappa=None, simplex_flag=False):
absolute_val = abs(self)
#next 2 lines actually compute the SufOR for little indian encoding
@@ -557,17 +583,32 @@ class sbitint(_bitint, _number, sbits):
bits = self.bit_decompose()
bits += [bits[-1]] * (n - len(bits))
return self.get_type(n).bit_compose(bits)
def __mul__(self, other):
if isinstance(other, sbitintvec):
return other * self
else:
return super(sbitint, self).__mul__(other)
class sbitintvec(sbitvec):
def __add__(self, other):
if other is 0:
return self
assert(len(self.v) == len(other.v))
return self.from_vec(sbitint.bit_adder(self.v, other.v))
v = sbitint.bit_adder(self.v, other.v)
return self.from_vec(v)
__radd__ = __add__
def less_than(self, other, *args, **kwargs):
assert(len(self.v) == len(other.v))
return self.from_vec(sbitint.bit_less_than(self.v, other.v))
def __mul__(self, other):
assert isinstance(other, sbitint)
matrix = [[x * b for x in self.v] for b in other.bit_decompose()]
v = sbitint.wallace_tree_from_matrix(matrix)
return self.from_vec(v)
__rmul__ = __mul__
reduce_after_mul = lambda x: x
sbitint.vec = sbitintvec
class cbitfix(object):
def __init__(self, value):
@@ -585,6 +626,13 @@ class sbitfix(_fix):
def set_precision(cls, f, k=None):
super(cls, sbitfix).set_precision(f, k)
cls.int_type = sbitint.get_type(cls.k)
@classmethod
def load_mem(cls, address, size=None):
if size not in (None, 1):
v = [cls.int_type.load_mem(address + i) for i in range(size)]
return sbitfixvec._new(sbitintvec(v))
else:
return super(sbitfix, cls).load_mem(address)
def __xor__(self, other):
return type(self)(self.v ^ other.v)
def __mul__(self, other):
@@ -596,3 +644,17 @@ class sbitfix(_fix):
__rmul__ = __mul__
sbitfix.set_precision(20, 41)
class sbitfixvec(_fix):
int_type = sbitintvec
float_type = type(None)
@staticmethod
@property
def f():
return sbitfix.f
@staticmethod
@property
def k():
return sbitfix.k
sbitfix.vec = sbitfixvec

View File

@@ -43,8 +43,7 @@ class StraightlineAllocator:
if base.vector:
for i,r in enumerate(base.vector):
r.i = self.alloc[base] + i
else:
base.i = self.alloc[base]
base.i = self.alloc[base]
def dealloc_reg(self, reg, inst, free):
self.dealloc.add(reg)
@@ -57,6 +56,7 @@ class StraightlineAllocator:
return
free[reg.reg_type, base.size].add(self.alloc[base])
if inst.is_vec() and base.vector:
self.defined[base] = inst
for i in base.vector:
self.defined[i] = inst
else:

View File

@@ -108,67 +108,54 @@ def Trunc(d, a, k, m, kappa, signed):
def TruncRing(d, a, k, m, signed):
a_prime = Mod2mRing(None, a, k, m, signed)
a -= a_prime
res = TruncZeroesInRing(a, k, m, signed)
res = TruncLeakyInRing(a, k, m, signed)
if d is not None:
movs(d, res)
return res
def TruncZeroesInRing(a, k, m, signed):
def TruncZeroes(a, k, m, signed):
if program.options.ring:
return TruncLeakyInRing(a, k, m, signed)
else:
import types
tmp = types.cint()
inv2m(tmp, m)
return a * tmp
def TruncLeakyInRing(a, k, m, signed):
"""
Returns a >> m.
Requires 2^m | a and a < 2^k.
Requires a < 2^k and leaks a % 2^m (needs to be constant or random).
"""
assert k > m
assert int(program.options.ring) >= k
from types import sint, intbitint, cint, cgf2n
n_bits = k - m
n_shift = int(program.options.ring) - n_bits
r_bits = [sint.get_random_bit() for i in range(n_bits)]
r = sint.bit_compose(r_bits)
shifted = ((a << (n_shift - m)) - (r << n_shift)).reveal()
masked = shifted >> n_shift
res_bits = intbitint.bit_adder(r_bits, masked.bit_decompose(n_bits))
res = sint.bit_compose(res_bits)
if signed:
res = sint.conv(res_bits[-1].if_else(res - (sint(1) << n_bits),
res))
a += (1 << (k - 1))
shifted = ((a << (n_shift - m)) + (r << n_shift)).reveal()
masked = shifted >> n_shift
u = sint()
BitLTL(u, masked, r_bits, 0)
res = (u << n_bits) + masked - r
if signed:
res -= (1 << (n_bits - 1))
return res
def TruncRoundNearest(a, k, m, kappa):
def TruncRoundNearest(a, k, m, kappa, signed=False):
"""
Returns a / 2^m, rounded to the nearest integer.
k: bit length of m
k: bit length of a
m: compile-time integer
"""
from types import sint, cint
from library import reveal, load_int_to_secret
if m == 1:
if program.options.ring:
lsb = Mod2mRing(None, a, k, 1, False)
return TruncRing(None, a + lsb, k + 1, 1, False)
else:
lsb = sint()
Mod2(lsb, a, k, kappa, False)
return (a + lsb) / 2
r_dprime = sint()
r_prime = sint()
r = [sint() for i in range(m)]
u = sint()
PRandM(r_dprime, r_prime, r, k, m, kappa)
c = reveal((cint(1) << (k - 1)) + a + (cint(1) << m) * r_dprime + r_prime)
c_prime = c % (cint(1) << (m - 1))
if const_rounds:
BitLTC1(u, c_prime, r[:-1], kappa)
else:
BitLTL(u, c_prime, r[:-1], kappa)
bit = ((c - c_prime) >> (m - 1)) % 2
xor = bit + u - 2 * bit * u
prod = xor * r[-1]
# u_prime = xor * u + (1 - xor) * r[-1]
u_prime = bit * u + u - 2 * bit * u + r[-1] - prod
a_prime = (c % (cint(1) << m)) - r_prime + (cint(1) << m) * u_prime
d = (a - a_prime) >> m
rounding = xor + r[-1] - 2 * prod
return d + rounding
from types import sint
res = sint()
Trunc(res, a + (1 << (m - 1)), k + 1, m, kappa, signed)
return res
def Mod2m(a_prime, a, k, m, kappa, signed):
"""

View File

@@ -369,6 +369,8 @@ def Trunc(a, l, m, kappa, compute_modulo=False):
x, pow2m = B2U(m, l, kappa)
#assert(pow2m.value == 2**m.value)
#assert(sum(b.value for b in x) == m.value)
if program.Program.prog.options.ring and not compute_modulo:
return TruncInRing(a, l, pow2m)
for i in range(l):
bit(r[i])
t1 = two_power(i) * r[i]
@@ -418,7 +420,7 @@ def TruncRoundNearestAdjustOverflow(a, length, target_length, kappa):
overflow = t.greater_equal(two_power(target_length), target_length + 1, kappa)
if program.Program.prog.options.ring:
s = (1 - overflow) * t + \
comparison.TruncZeroesInRing(overflow * t, length, 1, False)
comparison.TruncLeakyInRing(overflow * t, length, 1, False)
else:
s = (1 - overflow) * t + overflow * t / 2
return s, overflow
@@ -484,9 +486,22 @@ def TruncPr(a, k, m, kappa=None):
def TruncPrRing(a, k, m):
if m == 0:
return a
res = types.sint()
comparison.TruncRing(res, a, k, m, True)
return res
n_ring = int(program.Program.prog.options.ring)
if k == n_ring:
for i in range(m):
a += types.sint.get_random_bit() << i
return comparison.TruncLeakyInRing(a, k, m, True)
else:
from types import sint
# extra bit to mask overflow
r_bits = [sint.get_random_bit() for i in range(k + 1)]
n_shift = n_ring - len(r_bits)
tmp = a + sint.bit_compose(r_bits)
masked = (tmp << n_shift).reveal()
shifted = (masked << 1 >> (n_shift + m + 1))
overflow = r_bits[-1].bit_xor(masked >> (n_ring - 1))
res = shifted - sint.bit_compose(r_bits[m:k]) + (overflow << (k - m))
return res
def TruncPrField(a, k, m, kappa=None):
if kappa is None:
@@ -504,27 +519,26 @@ def TruncPrField(a, k, m, kappa=None):
d = (a - a_prime) / two_to_m
return d
def SDiv(a, b, l, kappa):
def SDiv(a, b, l, kappa, round_nearest=False):
theta = int(ceil(log(l / 3.5) / log(2)))
alpha = two_power(2*l)
beta = 1 / types.cint(two_power(l))
w = types.cint(int(2.9142 * two_power(l))) - 2 * b
x = alpha - b * w
y = a * w
y = TruncPr(y, 2 * l, l, kappa)
y = y.round(2 * l + 1, l, kappa, round_nearest)
x2 = types.sint()
comparison.Mod2m(x2, x, 2 * l + 1, l, kappa, False)
x1 = (x - x2) * beta
x1 = comparison.TruncZeroes(x - x2, 2 * l + 1, l, True)
for i in range(theta-1):
y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa)
y = TruncPr(y, 2 * l + 1, l + 1, kappa)
x = x1 * x2 + TruncPr(x2**2, 2 * l + 1, l + 1, kappa)
x = x1 * x1 + TruncPr(x, 2 * l + 1, l - 1, kappa)
y = y * (x1 + two_power(l)) + (y * x2).round(2 * l, l, kappa, round_nearest)
y = y.round(2 * l + 1, l + 1, kappa, round_nearest)
x = x1 * x2 + (x2**2).round(2 * l + 1, l + 1, kappa, round_nearest)
x = x1 * x1 + x.round(2 * l + 1, l - 1, kappa, round_nearest)
x2 = types.sint()
comparison.Mod2m(x2, x, 2 * l, l, kappa, False)
x1 = (x - x2) * beta
y = y * (x1 + two_power(l)) + TruncPr(y * x2, 2 * l, l, kappa)
y = TruncPr(y, 2 * l + 1, l - 1, kappa)
x1 = comparison.TruncZeroes(x - x2, 2 * l + 1, l, True)
y = y * (x1 + two_power(l)) + (y * x2).round(2 * l, l, kappa, round_nearest)
y = y.round(2 * l + 1, l - 1, kappa, round_nearest)
return y
def SDiv_mono(a, b, l, kappa):

View File

@@ -933,13 +933,6 @@ class print_reg_plain(base.IOInstruction):
code = base.opcodes['PRINTREGPLAIN']
arg_format = ['c']
@base.vectorize
class print_float_plain(base.IOInstruction):
__slots__ = []
code = base.opcodes['PRINTFLOATPLAIN']
arg_format = ['c', 'c', 'c', 'c']
class print_int(base.IOInstruction):
r""" Print only the value of register \verb|ci| to stdout. """
__slots__ = []
@@ -1358,10 +1351,7 @@ class muls(base.VarArgsInstruction, base.DataInstruction):
data_type = 'triple'
def get_repeat(self):
if program.options.ring:
return 0
else:
return len(self.args) / 3
return len(self.args) / 3
# def expand(self):
# s = [program.curr_block.new_reg('s') for i in range(9)]
@@ -1378,6 +1368,73 @@ class muls(base.VarArgsInstruction, base.DataInstruction):
# adds(s[8], s[7], s[6])
# addm(self.args[0], s[8], c[2])
@base.gf2n
class mulrs(base.VarArgsInstruction, base.DataInstruction):
""" Secret multiplication $s_i = s_j \cdot s_k$. """
__slots__ = []
code = base.opcodes['MULRS']
arg_format = tools.cycle(['int','sw','s','s'])
data_type = 'triple'
is_vec = lambda self: True
def __init__(self, res, x, y):
assert y.size == 1
assert res.size == x.size
base.Instruction.__init__(self, res.size, res, x, y)
def get_repeat(self):
return sum(self.args[::4])
def get_def(self):
return sum((arg.get_all() for arg in self.args[1::4]), [])
def get_used(self):
return sum((arg.get_all()
for arg in self.args[2::4] + self.args[3::4]), [])
@base.gf2n
class dotprods(base.VarArgsInstruction, base.DataInstruction):
""" Secret dot product. """
__slots__ = []
code = base.opcodes['DOTPRODS']
data_type = 'triple'
def __init__(self, *args):
flat_args = []
for i in range(0, len(args), 3):
res, x, y = args[i:i+3]
assert len(x) == len(y)
flat_args += [2 * len(x) + 2, res]
for x, y in zip(x, y):
flat_args += [x, y]
base.Instruction.__init__(self, *flat_args)
@property
def arg_format(self):
field = 'g' if self.is_gf2n() else ''
for i in self.bases():
yield 'int'
yield 's' + field + 'w'
for j in range(self.args[i] - 2):
yield 's' + field
def bases(self):
i = 0
while i < len(self.args):
yield i
i += self.args[i]
def get_repeat(self):
return sum(self.args[i] / 2 for i in self.bases())
def get_def(self):
return [self.args[i + 1] for i in self.bases()]
def get_used(self):
for i in self.bases():
for reg in self.args[i + 2:i + self.args[i]]:
yield reg
###
### CISC-style instructions
###

View File

@@ -87,6 +87,8 @@ opcodes = dict(
# Open
OPEN = 0xA5,
MULS = 0xA6,
MULRS = 0xA7,
DOTPRODS = 0xA8,
# Data access
TRIPLE = 0x50,
BIT = 0x51,
@@ -177,19 +179,14 @@ def int_to_bytes(x):
return [(x >> 8*i) % 256 for i in (3,2,1,0)]
global_vector_size = 1
global_vector_size_depth = 0
global_vector_size_stack = []
global_instruction_type_stack = ['modp']
def set_global_vector_size(size):
global global_vector_size, global_vector_size_depth
if size == 1:
stack = global_vector_size_stack
if size == 1 and not stack:
return
if global_vector_size == 1 or global_vector_size == size:
global_vector_size = size
global_vector_size_depth += 1
else:
raise CompilerError('Cannot set global vector size when already set')
stack.append(size)
def set_global_instruction_type(t):
if t == 'modp' or t == 'gf2n':
@@ -198,17 +195,19 @@ def set_global_instruction_type(t):
raise CompilerError('Invalid type %s for setting global instruction type')
def reset_global_vector_size():
global global_vector_size, global_vector_size_depth
if global_vector_size_depth > 0:
global_vector_size_depth -= 1
if global_vector_size_depth == 0:
global_vector_size = 1
stack = global_vector_size_stack
if global_vector_size_stack:
stack.pop()
def reset_global_instruction_type():
global_instruction_type_stack.pop()
def get_global_vector_size():
return global_vector_size
stack = global_vector_size_stack
if stack:
return stack[-1]
else:
return 1
def get_global_instruction_type():
return global_instruction_type_stack[-1]
@@ -243,10 +242,17 @@ def vectorize(instruction, global_dict=None):
@functools.wraps(instruction)
def maybe_vectorized_instruction(*args, **kwargs):
if global_vector_size == 1:
size = get_global_vector_size()
for arg in args:
try:
size = arg.size
break
except:
pass
if size == 1:
return instruction(*args, **kwargs)
else:
return Vectorized_Instruction(global_vector_size, *args, **kwargs)
return Vectorized_Instruction(size, *args, **kwargs)
maybe_vectorized_instruction.vec_ins = Vectorized_Instruction
maybe_vectorized_instruction.std_ins = instruction
@@ -287,6 +293,8 @@ def gf2n(instruction):
else:
__format.append(__f[0] + 'g' + __f[1:])
arg_format[:] = __format
elif isinstance(arg_format, property):
pass
else:
for __f in arg_format.args:
reformat(__f)

View File

@@ -1,4 +1,4 @@
from Compiler.types import cint,sint,cfix,sfix,sfloat,MPCThread,Array,MemValue,cgf2n,sgf2n,_number,_mem,_register,regint,Matrix,_types, cfloat
from Compiler.types import cint,sint,cfix,sfix,sfloat,MPCThread,Array,MemValue,cgf2n,sgf2n,_number,_mem,_register,regint,Matrix,_types, cfloat, _single
from Compiler.instructions import *
from Compiler.util import tuplify,untuplify
from Compiler import instructions,instructions_base,comparison,program,util
@@ -98,6 +98,7 @@ def print_ln_if(cond, s):
if cond:
print_ln(s)
else:
s += ' ' * ((len(s) + 3) % 4)
s += '\n'
while s:
cond.print_if(s[:4])
@@ -816,7 +817,7 @@ def map_reduce_single(n_parallel, n_loops, initializer, reducer, mem_state=None)
n_parallel = n_parallel or 1
if mem_state is None:
# default to list of MemValues to allow varying types
mem_state = [type(x).MemValue(x) for x in initializer()]
mem_state = [MemValue(x) for x in initializer()]
use_array = False
else:
# use Arrays for multithread version

View File

@@ -68,6 +68,10 @@ class Program(object):
Compiler.instructions.gasm_open_class, \
Compiler.instructions.muls_class, \
Compiler.instructions.gmuls_class, \
Compiler.instructions.mulrs_class, \
Compiler.instructions.gmulrs, \
Compiler.instructions.dotprods_class, \
Compiler.instructions.gdotprods, \
Compiler.instructions.asm_input_class, \
Compiler.instructions.gasm_input_class]
import Compiler.GC.instructions as gc
@@ -433,6 +437,7 @@ class Tape:
self.alloc_pool = scope.alloc_pool
else:
self.alloc_pool = defaultdict(set)
self.purged = False
def new_reg(self, reg_type, size=None):
return self.parent.new_reg(reg_type, size=size)
@@ -468,6 +473,23 @@ class Tape:
offset = self.get_offset(self.exit_block)
self.exit_condition.set_relative_jump(offset)
#print 'Basic block %d jumps to %d (%d)' % (next_block_index, jump_index, offset)
def purge(self):
relevant = lambda inst: inst.add_usage.__func__ is not \
Compiler.instructions_base.Instruction.add_usage.__func__
self.usage_instructions = filter(relevant, self.instructions)
del self.instructions
del self.defined_registers
self.purged = True
def add_usage(self, req_node):
if self.purged:
instructions = self.usage_instructions
else:
instructions = self.instructions
for inst in instructions:
inst.add_usage(req_node)
def __str__(self):
return self.name
@@ -507,6 +529,8 @@ class Tape:
self.outfile = self.program.programs_dir + '/Bytecode/' + self.name + '.bc'
def purge(self):
for block in self.basicblocks:
block.purge()
self._is_empty = (len(self.basicblocks) == 0)
del self.reg_values
del self.basicblocks
@@ -772,8 +796,7 @@ class Tape:
def aggregate(self, *args):
self.num = Tape.ReqNum()
for block in self.blocks:
for inst in block.instructions:
inst.add_usage(self)
block.add_usage(self)
res = reduce(lambda x,y: x + y.aggregate(self.name),
self.children, self.num)
return res
@@ -842,7 +865,7 @@ class Tape:
if size is None:
size = Compiler.instructions_base.get_global_vector_size()
self.size = size
if i:
if i is not None:
self.i = i
else:
self.i = program.reg_counter[reg_type]
@@ -878,23 +901,29 @@ class Tape:
raise CompilerError('Cannot reset size of vector register')
def set_vectorbase(self, vectorbase):
if self.vectorbase != self:
if self.vectorbase is not self:
raise CompilerError('Cannot assign one register' \
'to several vectors')
self.vectorbase = vectorbase
def _new_by_number(self, i):
return Tape.Register(self.reg_type, self.program, size=1, i=i)
def create_vector_elements(self):
if self.vector:
return
elif self.size == 1:
self.vector = [self]
return
self.vector = [self]
for i in range(1,self.size):
reg = Tape.Register(self.reg_type, self.program, size=1, i=self.i+i)
self.vector = []
for i in range(self.size):
reg = self._new_by_number(self.i + i)
reg.set_vectorbase(self)
self.vector.append(reg)
def get_all(self):
return self.vector or [self]
def __getitem__(self, index):
if not self.vector:
self.create_vector_elements()

File diff suppressed because it is too large Load Diff

View File

@@ -27,11 +27,11 @@ def greater_than(a, b, bits):
else:
return a.greater_than(b, bits)
def pow2(a, bits):
if isinstance(a, int):
def pow2_value(a, bit_length=None, security=None):
if is_constant_float(a):
return 2**a
else:
return a.pow2(bits)
return a.pow2(bit_length, security)
def mod2m(a, b, bits, signed):
if isinstance(a, int):
@@ -95,7 +95,16 @@ def cond_swap(cond, a, b):
def log2(x):
#print 'Compute log2 of', x
return int(math.ceil(math.log(x, 2)))
if is_constant_float(x):
return int(math.ceil(math.log(x, 2)))
else:
return x.log2()
def round_to_int(x):
if is_constant_float(x):
return int(round(x))
else:
return x.round_to_int()
def tree_reduce(function, sequence):
sequence = list(sequence)
@@ -165,3 +174,9 @@ def long_one(x):
except:
pass
return 1
def expand(x, size):
try:
return x.expand_to_vector(size)
except AttributeError:
return x

View File

@@ -340,12 +340,14 @@ void MultiEncCommit<FD>::add_ciphertexts(vector<Ciphertext>& ciphertexts,
template class SimpleEncCommitBase<gfp, FFT_Data, bigint>;
template class SimpleEncCommit<gfp, FFT_Data, bigint>;
template class SimpleEncCommitFactory<FFT_Data>;
template class SummingEncCommit<FFT_Data>;
template class NonInteractiveProofSimpleEncCommit<FFT_Data>;
template class MultiEncCommit<FFT_Data>;
template class SimpleEncCommitBase<gf2n_short, P2Data, int>;
template class SimpleEncCommit<gf2n_short, P2Data, int>;
template class SimpleEncCommitFactory<P2Data>;
template class SummingEncCommit<P2Data>;
template class NonInteractiveProofSimpleEncCommit<P2Data>;
template class MultiEncCommit<P2Data>;

View File

@@ -14,6 +14,7 @@
#include "Tools/benchmarking.h"
#include "Auth/fake-stuff.hpp"
#include "Processor/Data_Files.hpp"
#include <sstream>
#include <fstream>

View File

@@ -13,8 +13,9 @@
#include "Program.hpp"
#include "Thread.hpp"
#include "ThreadMaster.hpp"
#include "Auth/MaliciousRepMC.hpp"
#include "Processor/Replicated.hpp"
#include "Processor/Machine.hpp"
#include "Processor/Instruction.hpp"
namespace GC
{

View File

@@ -8,6 +8,7 @@
#include "Math/Setup.h"
#include "Auth/MaliciousRepMC.hpp"
#include "Processor/Data_Files.hpp"
namespace GC
{
@@ -61,7 +62,7 @@ void MaliciousRepThread::and_(Processor<MaliciousRepSecret>& processor,
int n_bits = args[i];
int left = args[i + 2];
int right = args[i + 3];
triples.push_back({0});
triples.push_back({{0}});
DataF.get(DATA_TRIPLE, triples.back().data());
shares.push_back((processor.S[left] - triples.back()[0]).mask(n_bits));
MaliciousRepSecret y_ext;

View File

@@ -13,7 +13,7 @@ union matrix32x8
__m256i whole;
octet rows[32];
matrix32x8(__m256i x = _mm256_setzero_si256()) : whole(x) {}
matrix32x8(const __m256i& x = _mm256_setzero_si256()) : whole(x) {}
matrix32x8(square64& input, int x, int y)
{
@@ -23,6 +23,7 @@ union matrix32x8
void transpose(square64& output, int x, int y)
{
#ifdef __AVX2__
for (int j = 0; j < 8; j++)
{
int row = _mm256_movemask_epi8(whole);
@@ -31,6 +32,10 @@ union matrix32x8
// _mm_movemask_epi8 uses most significant bit, hence +7-j
output.halfrows[8*x+7-j][y] = row;
}
#else
(void) output, (void) x, (void) y;
throw runtime_error("need to compile with AVX2 support");
#endif
}
};
@@ -51,8 +56,10 @@ case I: \
HIGHS = _mm256_unpackhi_epi##I(A, B); \
break;
void zip(int chunk_size, __m256i& lows, __m256i& highs, __m256i a, __m256i b)
void zip(int chunk_size, __m256i& lows, __m256i& highs,
const __m256i& a, const __m256i& b)
{
#ifdef __AVX2__
switch (chunk_size)
{
ZIP_CASE(8, lows, highs, a, b);
@@ -67,6 +74,10 @@ void zip(int chunk_size, __m256i& lows, __m256i& highs, __m256i a, __m256i b)
default:
throw invalid_argument("not supported");
}
#else
(void) chunk_size, (void) lows, (void) highs, (void) a, (void) b;
throw runtime_error("need to compile with AVX2 support");
#endif
}
void square64::transpose(int n_rows, int n_cols)

49
Machines/Rep.cpp Normal file
View File

@@ -0,0 +1,49 @@
/*
* Rep.cpp
*
*/
#include "Processor/Data_Files.hpp"
#include "Processor/Instruction.hpp"
#include "Processor/Machine.hpp"
template<>
Preprocessing<Rep3Share<gfp>>* Preprocessing<Rep3Share<gfp>>::get_live_prep(
SubProcessor<Rep3Share<gfp>>* proc)
{
return new ReplicatedPrep<Rep3Share<gfp>>(proc);
}
template<>
Preprocessing<Rep3Share<gf2n>>* Preprocessing<Rep3Share<gf2n>>::get_live_prep(
SubProcessor<Rep3Share<gf2n>>* proc)
{
return new ReplicatedPrep<Rep3Share<gf2n>>(proc);
}
template<>
Preprocessing<Rep3Share<Integer>>* Preprocessing<Rep3Share<Integer>>::get_live_prep(
SubProcessor<Rep3Share<Integer>>* proc)
{
return new ReplicatedRingPrep<Rep3Share<Integer>>(proc);
}
template<>
Preprocessing<MaliciousRep3Share<gfp>>* Preprocessing<MaliciousRep3Share<gfp>>::get_live_prep(
SubProcessor<MaliciousRep3Share<gfp>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousRep3Share<gfp>>(proc);
}
template<>
Preprocessing<MaliciousRep3Share<gf2n>>* Preprocessing<MaliciousRep3Share<gf2n>>::get_live_prep(
SubProcessor<MaliciousRep3Share<gf2n>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousRep3Share<gf2n>>(proc);
}
template class Machine<Rep3Share<Integer>, Rep3Share<gf2n>>;
template class Machine<Rep3Share<gfp>, Rep3Share<gf2n>>;
template class Machine<MaliciousRep3Share<gfp>, MaliciousRep3Share<gf2n>>;

6
Machines/SPDZ.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include "Processor/Data_Files.hpp"
#include "Processor/Instruction.hpp"
#include "Processor/Machine.hpp"
template class Machine<sgfp, Share<gf2n>>;

View File

@@ -3,13 +3,17 @@
*
*/
#include "ShamirMachine.h"
#include <Machines/ShamirMachine.h>
#include "Math/ShamirShare.h"
#include "Math/MaliciousShamirShare.h"
#include "Math/gfp.h"
#include "Math/gf2n.h"
#include "ReplicatedMachine.hpp"
#include "Processor/ReplicatedMachine.hpp"
#include "Processor/Data_Files.hpp"
#include "Processor/Instruction.hpp"
#include "Processor/Machine.hpp"
ShamirMachine* ShamirMachine::singleton = 0;
@@ -64,5 +68,38 @@ ShamirMachineSpec<T>::ShamirMachineSpec(int argc, const char** argv) :
ReplicatedMachine<T<gfp>, T<gf2n>>(argc, argv, "shamir", opt, nparties);
}
template<>
Preprocessing<ShamirShare<gfp>>* Preprocessing<ShamirShare<gfp>>::get_live_prep(
SubProcessor<ShamirShare<gfp>>* proc)
{
return new ReplicatedPrep<ShamirShare<gfp>>(proc);
}
template<>
Preprocessing<ShamirShare<gf2n>>* Preprocessing<ShamirShare<gf2n>>::get_live_prep(
SubProcessor<ShamirShare<gf2n>>* proc)
{
return new ReplicatedPrep<ShamirShare<gf2n>>(proc);
}
template<>
Preprocessing<MaliciousShamirShare<gfp>>* Preprocessing<MaliciousShamirShare<gfp>>::get_live_prep(
SubProcessor<MaliciousShamirShare<gfp>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousShamirShare<gfp>>(proc);
}
template<>
Preprocessing<MaliciousShamirShare<gf2n>>* Preprocessing<MaliciousShamirShare<gf2n>>::get_live_prep(
SubProcessor<MaliciousShamirShare<gf2n>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousShamirShare<gf2n>>(proc);
}
template class ShamirMachineSpec<ShamirShare>;
template class ShamirMachineSpec<MaliciousShamirShare>;
template class Machine<ShamirShare<gfp>, ShamirShare<gf2n>>;
template class Machine<MaliciousShamirShare<gfp>, MaliciousShamirShare<gf2n>>;

View File

@@ -3,8 +3,8 @@
*
*/
#ifndef PROCESSOR_SHAMIRMACHINE_H_
#define PROCESSOR_SHAMIRMACHINE_H_
#ifndef MACHINES_SHAMIRMACHINE_H_
#define MACHINES_SHAMIRMACHINE_H_
#include "Tools/ezOptionParser.h"
@@ -31,4 +31,4 @@ public:
ShamirMachineSpec(int argc, const char** argv);
};
#endif /* PROCESSOR_SHAMIRMACHINE_H_ */
#endif /* MACHINES_SHAMIRMACHINE_H_ */

View File

@@ -28,22 +28,25 @@ endif
COMMON = $(MATH) $(TOOLS) $(NETWORK) $(AUTH)
COMPLETE = $(COMMON) $(PROCESSOR) $(FHEOFFLINE) $(TINYOTOFFLINE) $(GC) $(OT)
YAO = $(patsubst %.cpp,%.o,$(wildcard Yao/*.cpp)) $(OT) $(GC)
BMR = $(patsubst %.cpp,%.o,$(wildcard BMR/*.cpp BMR/network/*.cpp)) $(COMMON) $(PROCESSOR)
BMR = $(patsubst %.cpp,%.o,$(wildcard BMR/*.cpp BMR/network/*.cpp)) $(COMMON) Processor/BaseMachine.o Processor/ProcessorBase.o
LIB = libSPDZ.a
LIBHM = libhm.a
LIBSIMPLEOT = SimpleOT/libsimpleot.a
# used for dependency generation
OBJS = $(BMR) $(FHEOFFLINE) $(TINYOTOFFLINE) $(YAO) $(COMPLETE)
OBJS = $(BMR) $(FHEOFFLINE) $(TINYOTOFFLINE) $(YAO) $(COMPLETE) $(patsubst %.cpp,%.o,$(wildcard Machines/*.cpp))
DEPS := $(OBJS:.o=.d)
all: gen_input online offline externalIO yao replicated shamir
ifeq ($(USE_GF2N_LONG),1)
ifneq ($(OS), Darwin)
all: bmr
endif
endif
ifeq ($(USE_NTL),1)
all: overdrive she-offline
@@ -78,21 +81,40 @@ rep-bin: replicated-bin-party.x malicious-rep-bin-party.x Fake-Offline.x
replicated: rep-field rep-ring rep-bin
tldr: malicious-rep-field-party.x Setup.x
tldr:
-echo ARCH = -march=native >> CONFIG.mine
$(MAKE) malicious-rep-field-party.x Setup.x
ifeq ($(OS), Darwin)
tldr: mac-setup
else
tldr: mpir
endif
shamir: shamir-party.x malicious-shamir-party.x galois-degree.x
Fake-Offline.x: Fake-Offline.cpp $(COMMON) $(PROCESSOR)
$(CXX) $(CFLAGS) -o $@ Fake-Offline.cpp $(COMMON) $(PROCESSOR) $(LDLIBS)
$(LIBHM): Machines/Rep.o Machines/ShamirMachine.o $(PROCESSOR) $(COMMON)
$(AR) -csr $@ $^
static/%.x: %.cpp $(LIBHM) $(LIBSIMPLEOT)
$(CXX) $(CFLAGS) -o $@ $^ -Wl,-Map=$<.map -Wl,-Bstatic -static-libgcc -static-libstdc++ $(BOOST) $(LDLIBS) -Wl,-Bdynamic -ldl
static-dir:
@ mkdir static 2> /dev/null; true
static-hm: static-dir $(patsubst %.cpp, static/%.x, $(wildcard *ring*.cpp *field*.cpp *shamir*.cpp ))
Fake-Offline.x: Fake-Offline.cpp $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
Check-Offline.x: Check-Offline.cpp $(COMMON) $(PROCESSOR) Auth/fake-stuff.hpp
$(CXX) $(CFLAGS) Check-Offline.cpp -o Check-Offline.x $(COMMON) $(PROCESSOR) $(LDLIBS)
$(CXX) $(CFLAGS) Check-Offline.cpp -o Check-Offline.x $(COMMON) $(LDLIBS)
Server.x: Server.cpp $(COMMON)
$(CXX) $(CFLAGS) Server.cpp -o Server.x $(COMMON) $(LDLIBS)
Player-Online.x: Player-Online.cpp $(COMMON) $(PROCESSOR)
$(CXX) $(CFLAGS) Player-Online.cpp -o Player-Online.x $(COMMON) $(PROCESSOR) $(LDLIBS)
Player-Online.x: Player-Online.cpp Machines/SPDZ.o $(COMMON) $(PROCESSOR)
$(CXX) $(CFLAGS) -o Player-Online.x $^ $(LDLIBS)
Setup.x: Setup.cpp $(COMMON)
$(CXX) $(CFLAGS) Setup.cpp -o Setup.x $(COMMON) $(LDLIBS)
@@ -134,13 +156,13 @@ endif
bmr-clean:
-rm BMR/*.o BMR/*/*.o GC/*.o
client-setup.x: client-setup.cpp $(COMMON) $(PROCESSOR)
client-setup.x: client-setup.cpp $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
bankers-bonus-client.x: ExternalIO/bankers-bonus-client.cpp $(COMMON) $(PROCESSOR)
bankers-bonus-client.x: ExternalIO/bankers-bonus-client.cpp $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
bankers-bonus-commsec-client.x: ExternalIO/bankers-bonus-commsec-client.cpp $(COMMON) $(PROCESSOR)
bankers-bonus-commsec-client.x: ExternalIO/bankers-bonus-commsec-client.cpp $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
ifeq ($(USE_NTL),1)
@@ -172,19 +194,19 @@ replicated-bin-party.x: $(COMMON) $(GC) replicated-bin-party.cpp
malicious-rep-bin-party.x: $(COMMON) $(GC) malicious-rep-bin-party.cpp
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
replicated-ring-party.x: replicated-ring-party.cpp $(PROCESSOR) $(COMMON)
replicated-ring-party.x: replicated-ring-party.cpp Machines/Rep.o $(PROCESSOR) $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
replicated-field-party.x: replicated-field-party.cpp $(PROCESSOR) $(COMMON)
replicated-field-party.x: replicated-field-party.cpp Machines/Rep.o $(PROCESSOR) $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
malicious-rep-field-party.x: malicious-rep-field-party.cpp $(PROCESSOR) $(COMMON)
malicious-rep-field-party.x: malicious-rep-field-party.cpp Machines/Rep.o $(PROCESSOR) $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
shamir-party.x: shamir-party.cpp $(PROCESSOR) $(COMMON)
shamir-party.x: shamir-party.cpp Machines/ShamirMachine.o $(PROCESSOR) $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
malicious-shamir-party.x: malicious-shamir-party.cpp $(PROCESSOR) $(COMMON)
malicious-shamir-party.x: malicious-shamir-party.cpp Machines/ShamirMachine.o $(PROCESSOR) $(COMMON)
$(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS)
$(LIBSIMPLEOT): SimpleOT/Makefile
@@ -196,15 +218,31 @@ OT/BaseOT.o: SimpleOT/Makefile
SimpleOT/Makefile:
git submodule update --init SimpleOT
.PHONY: mpir
mpir:
.PHONY: mpir-setup mpir-global mpir
mpir-setup:
git submodule update --init mpir
cd mpir; \
autoreconf -i; \
autoreconf -i; \
autoreconf -i
- $(MAKE) -C mpir clean
mpir-global: mpir-setup
cd mpir; \
./configure --enable-cxx;
$(MAKE) -C mpir
sudo $(MAKE) -C mpir install
mpir: mpir-setup
cd mpir; \
./configure --enable-cxx --prefix=$(CURDIR)/local
$(MAKE) -C mpir install
-echo MY_CFLAGS += -I./local/include >> CONFIG.mine
-echo MY_LDLIBS += -Wl,-rpath -Wl,./local/lib -L./local/lib >> CONFIG.mine
mac-setup:
brew install openssl boost libsodium mpir yasm
-echo MY_CFLAGS += -I/usr/local/opt/openssl/include >> CONFIG.mine
-echo MY_LDLIBS += -L/usr/local/opt/openssl/lib >> CONFIG.mine
clean:
-rm */*.o *.o */*.d *.d *.x core.* *.a gmon.out */*/*.o
-rm */*.o *.o */*.d *.d *.x core.* *.a gmon.out */*/*.o static/*.x

View File

@@ -17,6 +17,8 @@ public:
static char type_char() { return 'B'; }
static DataFieldType field_type() { return DATA_GF2; }
static bool allows(Dtype dtype) { return dtype == DATA_TRIPLE or dtype == DATA_BIT; }
BitVec() {}
BitVec(long a) : IntBase(a) {}
BitVec(const IntBase& a) : IntBase(a) {}

View File

@@ -27,6 +27,8 @@ public:
static void init_default(int lgp) { (void)lgp; }
static bool allows(Dtype type) { return type <= DATA_BIT; }
IntBase() { a = 0; }
IntBase(long a) : a(a) {}
@@ -79,7 +81,7 @@ class Integer : public IntBase
typedef Integer clear;
static char type_char() { return 'R'; }
static DataFieldType field_type() { return DATA_INT64; }
static DataFieldType field_type() { return DATA_INT; }
static void reqbl(int n);

View File

@@ -83,6 +83,11 @@ public:
*this = Rep3Share(aa, my_num) - S;
}
clear local_mul(const Rep3Share& other) const
{
return (*this)[0] * other.sum() + (*this)[1] * other[0];
}
void mul_by_bit(const Rep3Share& x, const T& y)
{
(void) x, (void) y;

View File

@@ -196,6 +196,7 @@ inline void Zp_Data::Sub(mp_limb_t* ans,const mp_limb_t* x,const mp_limb_t* y) c
}
}
#ifdef __BMI2__
template <int T>
inline void Zp_Data::Mont_Mult_(mp_limb_t* z,const mp_limb_t* x,const mp_limb_t* y) const
{
@@ -219,17 +220,20 @@ inline void Zp_Data::Mont_Mult_(mp_limb_t* z,const mp_limb_t* x,const mp_limb_t*
else
{ inline_mpn_copyi(z,ans+T,T); }
}
#endif
inline void Zp_Data::Mont_Mult(mp_limb_t* z,const mp_limb_t* x,const mp_limb_t* y) const
{
switch (t)
{
#ifdef __BMI2__
case 2:
Mont_Mult_<2>(z, x, y);
break;
case 1:
Mont_Mult_<1>(z, x, y);
break;
#endif
default:
Mont_Mult_variable(z, x, y);
break;

View File

@@ -7,7 +7,8 @@
#define MATH_FIELD_TYPES_H_
enum DataFieldType { DATA_MODP, DATA_GF2N, DATA_GF2, DATA_INT64, N_DATA_FIELD_TYPE };
enum DataFieldType { DATA_INT, DATA_GF2N, DATA_GF2, N_DATA_FIELD_TYPE };
enum Dtype { DATA_TRIPLE, DATA_SQUARE, DATA_BIT, DATA_INVERSE, DATA_BITTRIPLE, DATA_BITGF2NTRIPLE, N_DTYPE };
#endif /* MATH_FIELD_TYPES_H_ */

View File

@@ -91,7 +91,11 @@ void gf2n_short::init_field(int nn)
mask=(1ULL<<n)-1;
#ifdef __PCLMUL__
useC=(Check_CPU_support_AES()==0);
#else
useC = true;
#endif
}
@@ -222,6 +226,7 @@ void gf2n_short::mul(const gf2n_short& x,const gf2n_short& y)
}
else
{ /* Use Intel Instructions */
#ifdef __PCLMUL__
__m128i xx,yy,zz;
uint64_t c[] __attribute__((aligned (16))) = { 0,0 };
xx=_mm_set1_epi64x(x.a);
@@ -230,6 +235,9 @@ void gf2n_short::mul(const gf2n_short& x,const gf2n_short& y)
_mm_store_si128((__m128i*)c,zz);
lo=c[0];
hi=c[1];
#else
throw runtime_error("need to compile with PCLMUL support");
#endif
}
reduce(hi,lo);

View File

@@ -80,6 +80,8 @@ class gf2n_short
static int default_length() { return 40; }
static bool allows(Dtype type) { (void) type; return true; }
word get() const { return a; }
word get_word() const { return a; }

View File

@@ -31,9 +31,13 @@ public:
int128(const word& upper, const word& lower) : a(_mm_set_epi64x(upper, lower)) { }
word get_lower() const { return (word)_mm_cvtsi128_si64(a); }
word get_upper() const { return _mm_extract_epi64(a, 1); }
word get_upper() const { return _mm_cvtsi128_si64(_mm_unpackhi_epi64(a, a)); }
#ifdef __SSE41__
bool operator==(const int128& other) const { return _mm_test_all_zeros(a ^ other.a, a ^ other.a); }
#else
bool operator==(const int128& other) const { return get_lower() == other.get_lower() and get_upper() == other.get_upper(); }
#endif
bool operator!=(const int128& other) const { return !(*this == other); }
int128 operator<<(const int& other) const;
@@ -125,6 +129,8 @@ class gf2n_long
static int default_length() { return 128; }
static bool allows(Dtype type) { (void) type; return true; }
int128 get() const { return a; }
__m128i to_m128i() const { return a.a; }
word get_word() const { return _mm_cvtsi128_si64(a.a); }
@@ -278,10 +284,15 @@ inline void mul128(__m128i a, __m128i b, __m128i *res1, __m128i *res2)
{
__m128i tmp3, tmp4, tmp5, tmp6;
#ifdef __PCLMUL__
tmp3 = _mm_clmulepi64_si128(a, b, 0x00);
tmp4 = _mm_clmulepi64_si128(a, b, 0x10);
tmp5 = _mm_clmulepi64_si128(a, b, 0x01);
tmp6 = _mm_clmulepi64_si128(a, b, 0x11);
#else
(void) a, (void) b;
throw runtime_error("need to compile with PCLMUL support");
#endif
tmp4 = _mm_xor_si128(tmp4, tmp5);
tmp5 = _mm_slli_si128(tmp4, 8);

View File

@@ -151,6 +151,18 @@ void gfp::reqbl(int n)
}
}
bool gfp::allows(Dtype type)
{
switch(type)
{
case DATA_BITGF2NTRIPLE:
case DATA_BITTRIPLE:
return false;
default:
return true;
}
}
void to_signed_bigint(bigint& ans, const gfp& x)
{
to_bigint(ans, x);

View File

@@ -47,7 +47,7 @@ class gfp
static Zp_Data& get_ZpD()
{ return ZpD; }
static DataFieldType field_type() { return DATA_MODP; }
static DataFieldType field_type() { return DATA_INT; }
static char type_char() { return 'p'; }
static string type_string() { return "gfp"; }
@@ -55,6 +55,8 @@ class gfp
static void reqbl(int n);
static bool allows(Dtype type);
void assign(const gfp& g) { a=g.a; }
void assign_zero() { assignZero(a,ZpD); }
void assign_one() { assignOne(a,ZpD); }
@@ -108,7 +110,7 @@ class gfp
bool is_zero() const { return isZero(a,ZpD); }
bool is_one() const { return isOne(a,ZpD); }
bool is_one() const { return isOne(a,ZpD); }
bool is_bit() const { return is_zero() or is_one(); }
bool equal(const gfp& y) const { return areEqual(a,y.a,ZpD); }
bool operator==(const gfp& y) const { return equal(y); }

View File

@@ -192,6 +192,7 @@ inline void mpn_add_n_use_fixed(mp_limb_t* res, const mp_limb_t* x, const mp_lim
}
}
#ifdef __BMI2__
template <int L, int M, bool ADD>
inline void mpn_addmul_1_fixed__(mp_limb_t* res, const mp_limb_t* y, mp_limb_t x)
{
@@ -267,5 +268,6 @@ inline void mpn_mul_fixed(mp_limb_t* res, const mp_limb_t* x, const mp_limb_t* y
{
mpn_mul_fixed_<N + M, N, M>(res, x, y);
}
#endif
#endif /* MATH_MPN_FIXED_H_ */

View File

@@ -8,8 +8,8 @@
template <class T>
T operator*(const bool& x, const T& y) { return x ? y : T(); }
template <class T>
T operator*(const T& y, const bool& x) { return x ? y : T(); }
//template <class T>
//T operator*(const T& y, const bool& x) { return x ? y : T(); }
template <class T>
T& operator*=(const T& y, const bool& x) { y = x ? y : T(); return y; }

View File

@@ -76,6 +76,7 @@ CryptoPlayer::CryptoPlayer(const Names& Nms, int id_base) :
CryptoPlayer::~CryptoPlayer()
{
close_client_socket(plaintext_player.socket(my_num()));
plaintext_player.sockets.clear();
for (int i = 0; i < num_players(); i++)
delete sockets[i];

View File

@@ -188,10 +188,15 @@ template<>
MultiPlayer<int>::~MultiPlayer()
{
/* Close down the sockets */
for (int i=0; i<nplayers; i++)
close_client_socket(sockets[i]);
for (auto socket : sockets)
close_client_socket(socket);
close_client_socket(send_to_self_socket);
}
template<class T>
MultiPlayer<T>::~MultiPlayer()
{
}
Player::~Player()
{
@@ -336,6 +341,11 @@ void MultiPlayer<T>::exchange(int other, octetStream& o) const
sent += o.get_length();
}
void Player::exchange_relative(int offset, octetStream& o) const
{
exchange(get_player(offset), o);
}
template<class T>
void MultiPlayer<T>::pass_around(octetStream& o, int offset) const

View File

@@ -169,6 +169,10 @@ public:
void receive_relative(vector<octetStream>& o) const;
void receive_relative(int offset, octetStream& o) const;
// exchange data with minimal memory usage
void exchange(int other, octetStream& o) const = 0;
void exchange_relative(int offset, octetStream& o) const;
/* Broadcast and Receive data to/from all players
* - Assumes o[player_no] contains the thing broadcast by me
*/
@@ -204,7 +208,7 @@ public:
// portnum bases in each thread
MultiPlayer(const Names& Nms,int id_base=0);
virtual ~MultiPlayer() {}
virtual ~MultiPlayer();
T socket(int i) const { return sockets[i]; }

View File

@@ -151,7 +151,7 @@ void set_up_client_socket(int& mysocket,const char* hostname,int Portnum)
void close_client_socket(int socket)
{
if (close(socket) < 0 and errno != EBADF)
if (close(socket))
{
char tmp[1000];
sprintf(tmp, "close(%d)", socket);

View File

@@ -56,16 +56,27 @@ int get_ack(int socket);
extern unsigned long long sent_amount, sent_counter;
inline size_t send_non_blocking(int socket, octet* msg, size_t len)
{
int j = send(socket,msg,len,0);
if (j < 0)
{
if (errno != EINTR)
{ error("Send error - 1 "); }
else
return 0;
}
return j;
}
template<>
inline void send(int socket,octet *msg,size_t len)
{
size_t i = 0;
while (i < len)
{
int j = send(socket,msg+i,len-i,0);
i += j;
if (j < 0 and errno != EINTR)
{ error("Send error - 1 "); }
i += send_non_blocking(socket, msg + i, len - i);
}
sent_amount += len;

View File

@@ -14,12 +14,17 @@
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
inline size_t send_non_blocking(ssl_socket* socket, octet* data, size_t length)
{
return socket->write_some(boost::asio::buffer(data, length));
}
template<>
inline void send(ssl_socket* socket, octet* data, size_t length)
{
size_t sent = 0;
while (sent < length)
sent += socket->write_some(boost::asio::buffer(data + sent, length - sent));
sent += send_non_blocking(socket, data + sent, length - sent);
}
template<>

View File

@@ -384,8 +384,7 @@ bool square128::operator==(square128& other)
{
for (int i = 0; i < 128; i++)
{
__m128i tmp = rows[i] ^ other.rows[i];
if (not _mm_test_all_zeros(tmp, tmp))
if (int128(rows[i]) != other.rows[i])
return false;
}
return true;

View File

@@ -137,7 +137,7 @@ class BitVector
memcpy(bytes + offset, (octet*)&w, sizeof(word));
}
int128 get_int128(int i) const { return _mm_lddqu_si128((__m128i*)bytes + i); }
int128 get_int128(int i) const { return _mm_loadu_si128((__m128i*)bytes + i); }
void set_int128(int i, int128 a) { *((__m128i*)bytes + i) = a.a; }
int get_bit(int i) const

View File

@@ -143,6 +143,15 @@ int main(int argc, const char** argv)
"-N", // Flag token.
"--nparties" // Flag token.
);
opt.add(
"", // Default.
0, // Required?
0, // Number of args expected.
0, // Delimiter if expecting multiple args.
"Use encrypted channels.", // Help description.
"-e", // Flag token.
"--encrypted" // Flag token.
);
opt.resetArgs();
opt.parse(argc, argv);
@@ -250,7 +259,8 @@ int main(int argc, const char** argv)
{
Machine<sgfp, Share<gf2n>>(playerno, playerNames, progname, memtype, lg2,
opt.get("--direct")->isSet, opening_sum, opt.get("--parallel")->isSet,
opt.get("--threads")->isSet, max_broadcast, false, false,
opt.get("--threads")->isSet, max_broadcast,
opt.get("--encrypted")->isSet, false,
online_opts).run();
if (server)

94
Processor/BaseMachine.cpp Normal file
View File

@@ -0,0 +1,94 @@
/*
* BaseMachine.cpp
*
*/
#include "BaseMachine.h"
#include <iostream>
using namespace std;
BaseMachine* BaseMachine::singleton = 0;
BaseMachine& BaseMachine::s()
{
if (singleton)
return *singleton;
else
throw runtime_error("no singleton");
}
BaseMachine::BaseMachine() : nthreads(0)
{
if (not singleton)
singleton = this;
}
void BaseMachine::load_schedule(string progname)
{
this->progname = progname;
string fname = "Programs/Schedules/" + progname + ".sch";
cerr << "Opening file " << fname << endl;
inpf.open(fname);
if (inpf.fail()) { throw file_error("Missing '" + fname + "'. Did you compile '" + progname + "'?"); }
int nprogs;
inpf >> nthreads;
inpf >> nprogs;
cerr << "Number of threads I will run in parallel = " << nthreads << endl;
cerr << "Number of program sequences I need to load = " << nprogs << endl;
// Load in the programs
string threadname;
for (int i=0; i<nprogs; i++)
{ inpf >> threadname;
string filename = "Programs/Bytecode/" + threadname + ".bc";
cerr << "Loading program " << i << " from " << filename << endl;
load_program(threadname, filename);
}
}
void BaseMachine::print_compiler()
{
char compiler[1000];
inpf.get();
inpf.getline(compiler, 1000);
if (compiler[0] != 0)
cerr << "Compiler: " << compiler << endl;
inpf.close();
}
void BaseMachine::load_program(string threadname, string filename)
{
(void)threadname;
(void)filename;
throw not_implemented();
}
void BaseMachine::time()
{
cout << "Elapsed time: " << timer[0].elapsed() << endl;
}
void BaseMachine::start(int n)
{
cout << "Starting timer " << n << " at " << timer[n].elapsed()
<< " after " << timer[n].idle() << endl;
timer[n].start();
}
void BaseMachine::stop(int n)
{
timer[n].stop();
cout << "Stopped timer " << n << " at " << timer[n].elapsed() << endl;
}
void BaseMachine::print_timers()
{
cerr << "Time = " << timer[0].elapsed() << " seconds " << endl;
timer.erase(0);
for (map<int,Timer>::iterator it = timer.begin(); it != timer.end(); it++)
cerr << "Time" << it->first << " = " << it->second.elapsed() << " seconds " << endl;
}

View File

@@ -7,22 +7,34 @@
#define PROCESSOR_BEAVER_H_
#include <vector>
#include <array>
using namespace std;
#include "Replicated.h"
template<class T> class SubProcessor;
template<class T> class MAC_Check_Base;
class Player;
template<class T>
class Beaver
class Beaver : public ProtocolBase<T>
{
vector<T> shares;
vector<typename T::clear> opened;
vector<array<T, 3>> triples;
typename vector<typename T::clear>::iterator it;
typename vector<array<T, 3>>::iterator triple;
SubProcessor<T>* proc;
public:
Player& P;
static void muls(const vector<int>& reg, SubProcessor<T>& proc,
MAC_Check_Base<T>& MC, int size);
Beaver(Player& P) : proc(0), P(P) {}
Beaver(Player& P) : P(P) {}
void init_mul(SubProcessor<T>* proc);
typename T::clear prepare_mul(const T& x, const T& y);
void exchange();
T finalize_mul();
};
#endif /* PROCESSOR_BEAVER_H_ */

View File

@@ -7,44 +7,46 @@
#include <array>
template<class T>
void Beaver<T>::muls(const vector<int>& reg, SubProcessor<T>& proc, MAC_Check_Base<T>& MC,
int size)
void Beaver<T>::init_mul(SubProcessor<T>* proc)
{
assert(reg.size() % 3 == 0);
int n = reg.size() / 3;
vector<T>& shares = proc.Sh_PO;
vector<typename T::clear>& opened = proc.PO;
this->proc = proc;
shares.clear();
vector<array<T, 3>> triples(n * size);
auto triple = triples.begin();
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
proc.DataF.get(DATA_TRIPLE, triple->data());
for (int k = 0; k < 2; k++)
shares.push_back(proc.S[reg[i * 3 + k + 1] + j] - (*triple)[k]);
triple++;
}
MC.POpen_Begin(opened, shares, proc.P);
MC.POpen_End(opened, shares, proc.P);
auto it = opened.begin();
triple = triples.begin();
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
typename T::clear masked[2];
T& tmp = (*triple)[2];
for (int k = 0; k < 2; k++)
{
masked[k] = *it++;
tmp += (masked[k] * (*triple)[1 - k]);
}
tmp.add(tmp, masked[0] * masked[1], proc.P.my_num(), MC.get_alphai());
proc.S[reg[i * 3] + j] = tmp;
triple++;
}
opened.clear();
triples.clear();
}
template<class T>
typename T::clear Beaver<T>::prepare_mul(const T& x, const T& y)
{
triples.push_back({{}});
auto& triple = triples.back();
proc->DataF.get(DATA_TRIPLE, triple.data());
shares.push_back(x - triple[0]);
shares.push_back(y - triple[1]);
return 0;
}
template<class T>
void Beaver<T>::exchange()
{
proc->MC.POpen(opened, shares, P);
it = opened.begin();
triple = triples.begin();
}
template<class T>
T Beaver<T>::finalize_mul()
{
typename T::clear masked[2];
T& tmp = (*triple)[2];
for (int k = 0; k < 2; k++)
{
masked[k] = *it++;
tmp += (masked[k] * (*triple)[1 - k]);
}
tmp.add(tmp, masked[0] * masked[1], P.my_num(), proc->MC.get_alphai());
triple++;
return tmp;
}

View File

@@ -9,7 +9,7 @@
#include "Math/gf2n.h"
#include "Math/Share.h"
#include "Math/field_types.h"
#include "Processor/Buffer.h"
#include "Tools/Buffer.h"
#include "Processor/InputTuple.h"
#include "Tools/Lock.h"
#include "Networking/Player.h"
@@ -18,8 +18,6 @@
#include <map>
using namespace std;
enum Dtype { DATA_TRIPLE, DATA_SQUARE, DATA_BIT, DATA_INVERSE, DATA_BITTRIPLE, DATA_BITGF2NTRIPLE, N_DTYPE };
class DataTag
{
int t[4];
@@ -95,8 +93,6 @@ class Sub_Data_Files : public Preprocessing<T>
{
template<class U> friend class Sub_Data_Files;
static const bool implemented[N_DTYPE];
static map<DataTag, int> tuple_lengths;
static Lock tuple_lengths_lock;

View File

@@ -9,77 +9,17 @@
#include "Math/MaliciousShamirShare.h"
#include "Processor/MaliciousRepPrep.hpp"
#include "Processor/Replicated.hpp"
//#include "Processor/Replicated.hpp"
#include "Processor/ReplicatedPrep.hpp"
#include "Processor/Input.hpp"
#include "Processor/ReplicatedInput.hpp"
#include "Processor/Shamir.hpp"
#include "Auth/MaliciousShamirMC.hpp"
//#include "Processor/Input.hpp"
//#include "Processor/ReplicatedInput.hpp"
//#include "Processor/Shamir.hpp"
//#include "Auth/MaliciousShamirMC.hpp"
#include <iomanip>
#include <numeric>
const char* DataPositions::field_names[] = { "gfp", "gf2n", "bit", "int64" };
template<>
const bool Sub_Data_Files<sgfp>::implemented[N_DTYPE] =
{ true, true, true, true, false, false }
;
template<>
const bool Sub_Data_Files<Share<gf2n>>::implemented[N_DTYPE] =
{ true, true, true, true, true, true }
;
template<>
const bool Sub_Data_Files<Rep3Share<Integer>>::implemented[N_DTYPE] =
{ false, false, true, false, false, false }
;
template<>
const bool Sub_Data_Files<Rep3Share<gfp>>::implemented[N_DTYPE] =
{ true, true, true, true, false, false }
;
template<>
const bool Sub_Data_Files<Rep3Share<gf2n>>::implemented[N_DTYPE] =
{ true, true, true, true, false, false }
;
template<>
const bool Sub_Data_Files<MaliciousRep3Share<gfp>>::implemented[N_DTYPE] =
{ true, true, true, true, false, false }
;
template<>
const bool Sub_Data_Files<MaliciousRep3Share<gf2n>>::implemented[N_DTYPE] =
{ true, true, true, true, false, false }
;
template<>
const bool Sub_Data_Files<GC::MaliciousRepSecret>::implemented[N_DTYPE] =
{ true, false, true, false, false, false }
;
template<>
const bool Sub_Data_Files<ShamirShare<gfp>>::implemented[N_DTYPE] =
{ false, false, false, false, false, false }
;
template<>
const bool Sub_Data_Files<ShamirShare<gf2n>>::implemented[N_DTYPE] =
{ false, false, false, false, false, false }
;
template<>
const bool Sub_Data_Files<MaliciousShamirShare<gfp>>::implemented[N_DTYPE] =
{ false, false, false, false, false, false }
;
template<>
const bool Sub_Data_Files<MaliciousShamirShare<gf2n>>::implemented[N_DTYPE] =
{ false, false, false, false, false, false }
;
const char* DataPositions::field_names[] = { "int", "gf2n", "bit" };
const int DataPositions::tuple_size[N_DTYPE] = { 3, 2, 1, 2, 3, 3 };
@@ -88,73 +28,6 @@ Lock Sub_Data_Files<T>::tuple_lengths_lock;
template<class T>
map<DataTag, int> Sub_Data_Files<T>::tuple_lengths;
template<>
Preprocessing<Rep3Share<gfp>>* Preprocessing<Rep3Share<gfp>>::get_live_prep(
SubProcessor<Rep3Share<gfp>>* proc)
{
return new ReplicatedPrep<Rep3Share<gfp>>(proc);
}
template<>
Preprocessing<Rep3Share<gf2n>>* Preprocessing<Rep3Share<gf2n>>::get_live_prep(
SubProcessor<Rep3Share<gf2n>>* proc)
{
return new ReplicatedPrep<Rep3Share<gf2n>>(proc);
}
template<>
Preprocessing<Rep3Share<Integer>>* Preprocessing<Rep3Share<Integer>>::get_live_prep(
SubProcessor<Rep3Share<Integer>>* proc)
{
return new ReplicatedRingPrep<Rep3Share<Integer>>(proc);
}
template<>
Preprocessing<MaliciousRep3Share<gfp>>* Preprocessing<MaliciousRep3Share<gfp>>::get_live_prep(
SubProcessor<MaliciousRep3Share<gfp>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousRep3Share<gfp>>(proc);
}
template<>
Preprocessing<MaliciousRep3Share<gf2n>>* Preprocessing<MaliciousRep3Share<gf2n>>::get_live_prep(
SubProcessor<MaliciousRep3Share<gf2n>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousRep3Share<gf2n>>(proc);
}
template<>
Preprocessing<ShamirShare<gfp>>* Preprocessing<ShamirShare<gfp>>::get_live_prep(
SubProcessor<ShamirShare<gfp>>* proc)
{
return new ReplicatedPrep<ShamirShare<gfp>>(proc);
}
template<>
Preprocessing<ShamirShare<gf2n>>* Preprocessing<ShamirShare<gf2n>>::get_live_prep(
SubProcessor<ShamirShare<gf2n>>* proc)
{
return new ReplicatedPrep<ShamirShare<gf2n>>(proc);
}
template<>
Preprocessing<MaliciousShamirShare<gfp>>* Preprocessing<MaliciousShamirShare<gfp>>::get_live_prep(
SubProcessor<MaliciousShamirShare<gfp>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousShamirShare<gfp>>(proc);
}
template<>
Preprocessing<MaliciousShamirShare<gf2n>>* Preprocessing<MaliciousShamirShare<gf2n>>::get_live_prep(
SubProcessor<MaliciousShamirShare<gf2n>>* proc)
{
(void) proc;
return new MaliciousRepPrep<MaliciousShamirShare<gf2n>>(proc);
}
template<class T>
Preprocessing<T>* Preprocessing<T>::get_live_prep(SubProcessor<T>* proc)
{
@@ -270,7 +143,7 @@ Sub_Data_Files<T>::Sub_Data_Files(int my_num, int num_players,
string suffix = get_suffix(thread_num);
for (int dtype = 0; dtype < N_DTYPE; dtype++)
{
if (implemented[dtype])
if (T::clear::allows(Dtype(dtype)))
{
sprintf(filename,(prep_data_dir + "%s-%s-P%d%s").c_str(),DataPositions::dtype_names[dtype],
(T::type_short()).c_str(),my_num,suffix.c_str());
@@ -329,7 +202,7 @@ void Sub_Data_Files<T>::seekg(DataPositions& pos)
{
DataFieldType field_type = T::field_type();
for (int dtype = 0; dtype < N_DTYPE; dtype++)
if (implemented[dtype])
if (T::clear::allows(Dtype(dtype)))
buffers[dtype].seekg(pos.files[field_type][dtype]);
for (int j = 0; j < num_players; j++)
if (j == my_num)
@@ -437,19 +310,3 @@ void Sub_Data_Files<T>::get(vector<T>& S, DataTag tag, const vector<int>& regs,
for (unsigned int i = 0; i < regs.size(); i++)
extended[tag].input(S[regs[i] + j]);
}
template class Sub_Data_Files<Share<gf2n>>;
template class Sub_Data_Files<sgfp>;
template class Sub_Data_Files<Rep3Share<Integer>>;
template class Sub_Data_Files<Rep3Share<gfp>>;
template class Sub_Data_Files<Rep3Share<gf2n>>;
template class Sub_Data_Files<GC::MaliciousRepSecret>;
template class Sub_Data_Files<MaliciousRep3Share<gfp>>;
template class Sub_Data_Files<MaliciousRep3Share<gf2n>>;
template class Data_Files<sgfp, Share<gf2n>>;
template class Data_Files<Rep3Share<Integer>, Rep3Share<gf2n>>;
template class Data_Files<Rep3Share<gfp>, Rep3Share<gf2n>>;
template class Data_Files<MaliciousRep3Share<gfp>, MaliciousRep3Share<gf2n>>;
template class Data_Files<ShamirShare<gfp>, ShamirShare<gf2n>>;
template class Data_Files<MaliciousShamirShare<gfp>, MaliciousShamirShare<gf2n>>;

View File

@@ -10,7 +10,7 @@
using namespace std;
#include "Math/Share.h"
#include "Processor/Buffer.h"
#include "Tools/Buffer.h"
#include "Tools/time-func.h"
class ArithmeticProcessor;

View File

@@ -92,6 +92,8 @@ enum
// Open
OPEN = 0xA5,
MULS = 0xA6,
MULRS = 0xA7,
DOTPRODS = 0xA8,
// Data access
TRIPLE = 0x50,
BIT = 0x51,
@@ -214,6 +216,8 @@ enum
// Open
GOPEN = 0x1A5,
GMULS = 0x1A6,
GMULRS = 0x1A7,
GDOTPRODS = 0x1A8,
// Data access
GTRIPLE = 0x150,
GBIT = 0x151,

View File

@@ -11,15 +11,15 @@
#include "Auth/ShamirMC.h"
#include "Math/MaliciousShamirShare.h"
#include "Processor/Processor.hpp"
//#include "Processor/Processor.hpp"
#include "Processor/Binary_File_IO.hpp"
#include "Processor/Input.hpp"
#include "Processor/Beaver.hpp"
#include "Processor/Shamir.hpp"
#include "Processor/ShamirInput.hpp"
#include "Processor/Replicated.hpp"
#include "Auth/MaliciousRepMC.hpp"
#include "Auth/ShamirMC.hpp"
//#include "Processor/Input.hpp"
//#include "Processor/Beaver.hpp"
//#include "Processor/Shamir.hpp"
//#include "Processor/ShamirInput.hpp"
//#include "Processor/Replicated.hpp"
//#include "Auth/MaliciousRepMC.hpp"
//#include "Auth/ShamirMC.hpp"
#include <stdlib.h>
#include <algorithm>
@@ -33,6 +33,7 @@
#undef DEBUG
// Convert modp to signed bigint of a given bit length
inline
void to_signed_bigint(bigint& bi, const gfp& x, int len)
{
to_bigint(bi, x);
@@ -53,7 +54,7 @@ void to_signed_bigint(bigint& bi, const gfp& x, int len)
bi = -bi;
}
inline
void Instruction::parse(istream& s)
{
n=0; start.resize(0);
@@ -70,7 +71,7 @@ void Instruction::parse(istream& s)
parse_operands(s, pos);
}
inline
void BaseInstruction::parse_operands(istream& s, int pos)
{
int num_var_args = 0;
@@ -277,7 +278,7 @@ void BaseInstruction::parse_operands(istream& s, int pos)
case CRASH:
case STARTGRIND:
case STOPGRIND:
break;
break;
// instructions with 4 register operands
case PRINTFLOATPLAIN:
get_vector(4, start, s);
@@ -288,6 +289,10 @@ void BaseInstruction::parse_operands(istream& s, int pos)
case GOPEN:
case MULS:
case GMULS:
case MULRS:
case GMULRS:
case DOTPRODS:
case GDOTPRODS:
case INPUT:
case GINPUT:
num_var_args = get_int(s);
@@ -385,7 +390,7 @@ void BaseInstruction::parse_operands(istream& s, int pos)
}
}
inline
bool Instruction::get_offline_data_usage(DataPositions& usage)
{
switch (opcode)
@@ -415,6 +420,7 @@ bool Instruction::get_offline_data_usage(DataPositions& usage)
}
}
inline
int BaseInstruction::get_reg_type() const
{
switch (opcode) {
@@ -451,10 +457,27 @@ int BaseInstruction::get_reg_type() const
}
}
inline
unsigned BaseInstruction::get_max_reg(int reg_type) const
{
if (get_reg_type() != reg_type) { return 0; }
switch (opcode)
{
case DOTPRODS:
{
int res = 0;
auto it = start.begin();
while (it != start.end())
{
int n = *it;
res = max(res, *it++);
it += n - 1;
}
return res;
}
}
const int *begin, *end;
if (start.size())
{
@@ -473,6 +496,7 @@ unsigned BaseInstruction::get_max_reg(int reg_type) const
return res + size;
}
inline
unsigned Instruction::get_mem(RegType reg_type, SecrecyType sec_type) const
{
if (get_reg_type() == reg_type and is_direct_memory_access(sec_type))
@@ -481,6 +505,7 @@ unsigned Instruction::get_mem(RegType reg_type, SecrecyType sec_type) const
return 0;
}
inline
bool BaseInstruction::is_direct_memory_access(SecrecyType sec_type) const
{
if (sec_type == SECRET)
@@ -514,7 +539,7 @@ bool BaseInstruction::is_direct_memory_access(SecrecyType sec_type) const
}
inline
ostream& operator<<(ostream& s,const Instruction& instr)
{
s << instr.opcode << " : ";
@@ -1386,6 +1411,18 @@ inline void Instruction::execute(Processor<sint, sgf2n>& Proc) const
case GMULS:
Proc.Proc2.protocol.muls(start, Proc.Proc2, Proc.MC2, size);
return;
case MULRS:
Proc.Procp.protocol.mulrs(start, Proc.Procp);
return;
case GMULRS:
Proc.Proc2.protocol.mulrs(start, Proc.Proc2);
return;
case DOTPRODS:
Proc.Procp.protocol.dotprods(start, Proc.Procp);
return;
case GDOTPRODS:
Proc.Proc2.protocol.dotprods(start, Proc.Proc2);
return;
case JMP:
Proc.PC += (signed int) n;
break;
@@ -1701,10 +1738,3 @@ void Program::execute(Processor<sint, sgf2n>& Proc) const
while (Proc.PC<size)
{ p[Proc.PC].execute(Proc); }
}
template void Program::execute(Processor<sgfp, Share<gf2n>>& Proc) const;
template void Program::execute(Processor<Rep3Share<Integer>, Rep3Share<gf2n>>& Proc) const;
template void Program::execute(Processor<Rep3Share<gfp>, Rep3Share<gf2n>>& Proc) const;
template void Program::execute(Processor<MaliciousRep3Share<gfp>, MaliciousRep3Share<gf2n>>& Proc) const;
template void Program::execute(Processor<ShamirShare<gfp>, ShamirShare<gf2n>>& Proc) const;
template void Program::execute(Processor<MaliciousShamirShare<gfp>, MaliciousShamirShare<gf2n>>& Proc) const;

View File

@@ -18,6 +18,7 @@
#include <vector>
#include <map>
#include <atomic>
using namespace std;
template<class sint, class sgf2n>
@@ -71,6 +72,8 @@ class Machine : public BaseMachine
OnlineOptions opts;
atomic<size_t> data_sent;
Machine(int my_number, Names& playerNames, string progname,
string memtype, int lg2, bool direct, int opening_sum, bool parallel,
bool receive_threads, int max_broadcast, bool use_encryption, bool live_prep,

View File

@@ -5,6 +5,7 @@
#include "ShamirInput.hpp"
#include "Shamir.hpp"
#include "Replicated.hpp"
#include "Beaver.hpp"
#include "Auth/ShamirMC.hpp"
#include "Auth/MaliciousShamirMC.hpp"
@@ -24,24 +25,6 @@
#include <pthread.h>
using namespace std;
BaseMachine* BaseMachine::singleton = 0;
BaseMachine& BaseMachine::s()
{
if (singleton)
return *singleton;
else
throw runtime_error("no singleton");
}
BaseMachine::BaseMachine() : nthreads(0)
{
if (singleton)
throw runtime_error("there can only be one");
else
singleton = this;
}
template<class sint, class sgf2n>
Machine<sint, sgf2n>::Machine(int my_number, Names& playerNames,
string progname_str, string memtype, int lg2, bool direct,
@@ -50,7 +33,8 @@ Machine<sint, sgf2n>::Machine(int my_number, Names& playerNames,
: my_number(my_number), N(playerNames), tn(0), numt(0), usage_unknown(false),
direct(direct), opening_sum(opening_sum), parallel(parallel),
receive_threads(receive_threads), max_broadcast(max_broadcast),
use_encryption(use_encryption), live_prep(live_prep), opts(opts)
use_encryption(use_encryption), live_prep(live_prep), opts(opts),
data_sent(0)
{
if (opening_sum < 2)
this->opening_sum = N.num_players();
@@ -166,42 +150,6 @@ Machine<sint, sgf2n>::Machine(int my_number, Names& playerNames,
}
}
void BaseMachine::load_schedule(string progname)
{
this->progname = progname;
string fname = "Programs/Schedules/" + progname + ".sch";
cerr << "Opening file " << fname << endl;
inpf.open(fname);
if (inpf.fail()) { throw file_error("Missing '" + fname + "'. Did you compile '" + progname + "'?"); }
int nprogs;
inpf >> nthreads;
inpf >> nprogs;
cerr << "Number of threads I will run in parallel = " << nthreads << endl;
cerr << "Number of program sequences I need to load = " << nprogs << endl;
// Load in the programs
string threadname;
for (int i=0; i<nprogs; i++)
{ inpf >> threadname;
string filename = "Programs/Bytecode/" + threadname + ".bc";
cerr << "Loading program " << i << " from " << filename << endl;
load_program(threadname, filename);
}
}
void BaseMachine::print_compiler()
{
char compiler[1000];
inpf.get();
inpf.getline(compiler, 1000);
if (compiler[0] != 0)
cerr << "Compiler: " << compiler << endl;
inpf.close();
}
template<class sint, class sgf2n>
void Machine<sint, sgf2n>::load_program(string threadname, string filename)
{
@@ -345,6 +293,7 @@ void Machine<sint, sgf2n>::run()
cerr << "Finish timer: " << finish_timer.elapsed() << endl;
cerr << "Process timer: " << proc_timer.elapsed() << endl;
print_timers();
cerr << "Data sent = " << data_sent / 1e6 << " MB" << endl;
if (opening_sum < N.num_players() && !direct)
cerr << "Summed at most " << opening_sum << " shares at once with indirect communication" << endl;
@@ -368,12 +317,6 @@ void Machine<sint, sgf2n>::run()
outf << M2 << Mp << Mi;
outf.close();
extern unsigned long long sent_amount, sent_counter;
cerr << "Data sent = " << sent_amount << " bytes in "
<< sent_counter << " calls,";
cerr << sent_amount / sent_counter / N.num_players()
<< " bytes per call" << endl;
for (int dtype = 0; dtype < N_DTYPE; dtype++)
{
cerr << "Num " << DataPositions::dtype_names[dtype] << "\t=";
@@ -407,48 +350,8 @@ string Machine<sint, sgf2n>::memory_filename()
return PREP_DIR "Memory-" + sint::type_short() + "-P" + to_string(my_number);
}
void BaseMachine::load_program(string threadname, string filename)
{
(void)threadname;
(void)filename;
throw not_implemented();
}
void BaseMachine::time()
{
cout << "Elapsed time: " << timer[0].elapsed() << endl;
}
void BaseMachine::start(int n)
{
cout << "Starting timer " << n << " at " << timer[n].elapsed()
<< " after " << timer[n].idle() << endl;
timer[n].start();
}
void BaseMachine::stop(int n)
{
timer[n].stop();
cout << "Stopped timer " << n << " at " << timer[n].elapsed() << endl;
}
void BaseMachine::print_timers()
{
cerr << "Time = " << timer[0].elapsed() << " seconds " << endl;
timer.erase(0);
for (map<int,Timer>::iterator it = timer.begin(); it != timer.end(); it++)
cerr << "Time" << it->first << " = " << it->second.elapsed() << " seconds " << endl;
}
template<class sint, class sgf2n>
void Machine<sint, sgf2n>::reqbl(int n)
{
sint::clear::reqbl(n);
}
template class Machine<sgfp, Share<gf2n>>;
template class Machine<Rep3Share<Integer>, Rep3Share<gf2n>>;
template class Machine<Rep3Share<gfp>, Rep3Share<gf2n>>;
template class Machine<MaliciousRep3Share<gfp>, MaliciousRep3Share<gf2n>>;
template class Machine<ShamirShare<gfp>, ShamirShare<gf2n>>;
template class Machine<MaliciousShamirShare<gfp>, MaliciousShamirShare<gf2n>>;

View File

@@ -5,7 +5,7 @@
#include "MaliciousRepPrep.h"
#include "Auth/Subroutines.h"
#include "Auth/MaliciousRepMC.hpp"
//#include "Auth/MaliciousRepMC.hpp"
template<class T>
MaliciousRepPrep<T>::MaliciousRepPrep(SubProcessor<T>* proc) :
@@ -41,7 +41,7 @@ template<class T>
void MaliciousRepPrep<T>::buffer_triples()
{
auto& triples = this->triples;
auto& buffer_size = this->buffer_size;
auto buffer_size = this->buffer_size;
clear_tmp();
Player& P = honest_prep.protocol->P;
triples.clear();
@@ -51,8 +51,8 @@ void MaliciousRepPrep<T>::buffer_triples()
T f, g, h;
honest_prep.get_three(DATA_TRIPLE, a, b, c);
honest_prep.get_three(DATA_TRIPLE, f, g, h);
triples.push_back({a, b, c});
check_triples.push_back({f, g, h});
triples.push_back({{a, b, c}});
check_triples.push_back({{f, g, h}});
}
auto t = Create_Random<typename T::clear>(P);
for (int i = 0; i < buffer_size; i++)
@@ -86,7 +86,7 @@ template<class T>
void MaliciousRepPrep<T>::buffer_squares()
{
auto& squares = this->squares;
auto& buffer_size = this->buffer_size;
auto buffer_size = this->buffer_size;
clear_tmp();
Player& P = honest_prep.protocol->P;
squares.clear();
@@ -96,8 +96,8 @@ void MaliciousRepPrep<T>::buffer_squares()
T f, h;
honest_prep.get_two(DATA_SQUARE, a, b);
honest_prep.get_two(DATA_SQUARE, f, h);
squares.push_back({a, b});
check_squares.push_back({f, h});
squares.push_back({{a, b}});
check_squares.push_back({{f, h}});
}
auto t = Create_Random<typename T::clear>(P);
for (int i = 0; i < buffer_size; i++)
@@ -132,7 +132,7 @@ template<class T>
void MaliciousRepPrep<T>::buffer_bits()
{
auto& bits = this->bits;
auto& buffer_size = this->buffer_size;
auto buffer_size = this->buffer_size;
clear_tmp();
Player& P = honest_prep.protocol->P;
bits.clear();
@@ -142,7 +142,7 @@ void MaliciousRepPrep<T>::buffer_bits()
honest_prep.get_one(DATA_BIT, a);
honest_prep.get_two(DATA_SQUARE, f, h);
bits.push_back(a);
check_squares.push_back({f, h});
check_squares.push_back({{f, h}});
}
auto t = Create_Random<typename T::clear>(P);
for (int i = 0; i < buffer_size; i++)

View File

@@ -170,6 +170,8 @@ void* Sub_Main_Func(void* ptr)
cerr << "Thread " << num << " timer: " << thread_timer.elapsed() << endl;
cerr << "Thread " << num << " wait timer: " << wait_timer.elapsed() << endl;
machine.data_sent += P.sent;
delete MC2;
delete MCp;
delete player;

View File

@@ -41,7 +41,7 @@ class SubProcessor
template<class sint, class sgf2n> friend class Processor;
template<class U> friend class SPDZ;
template<class U> friend class PrepLessProtocol;
template<class U> friend class ProtocolBase;
template<class U> friend class Beaver;
public:
@@ -61,7 +61,9 @@ public:
void POpen_Stop(const vector<int>& reg,const Player& P,int size);
void POpen(const vector<int>& reg,const Player& P,int size);
void muls(const vector<int>& reg,const Player& P,int size);
void muls(const vector<int>& reg, int size);
void mulrs(const vector<int>& reg);
void dotprods(const vector<int>& reg);
vector<T>& get_S()
{

View File

@@ -50,7 +50,7 @@ Processor<sint, sgf2n>::Processor(int thread_num,Player& P,
template<class sint, class sgf2n>
Processor<sint, sgf2n>::~Processor()
{
cerr << "Sent " << sent << " elements in " << rounds << " rounds" << endl;
cerr << "Opened " << sent << " elements in " << rounds << " rounds" << endl;
}
template<class sint, class sgf2n>
@@ -485,6 +485,85 @@ void SubProcessor<T>::POpen(const vector<int>& reg, const Player& P,
POpen_Stop(dest, P, size);
}
template<class T>
void SubProcessor<T>::muls(const vector<int>& reg, int size)
{
assert(reg.size() % 3 == 0);
int n = reg.size() / 3;
SubProcessor<T>& proc = *this;
protocol.init_mul(&proc);
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
auto& x = proc.S[reg[3 * i + 1] + j];
auto& y = proc.S[reg[3 * i + 2] + j];
protocol.prepare_mul(x, y);
}
protocol.exchange();
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
proc.S[reg[3 * i] + j] = protocol.finalize_mul();
}
protocol.counter += n * size;
}
template<class T>
void SubProcessor<T>::mulrs(const vector<int>& reg)
{
assert(reg.size() % 4 == 0);
int n = reg.size() / 4;
SubProcessor<T>& proc = *this;
protocol.init_mul(&proc);
for (int i = 0; i < n; i++)
for (int j = 0; j < reg[4 * i]; j++)
{
auto& x = proc.S[reg[4 * i + 2] + j];
auto& y = proc.S[reg[4 * i + 3]];
protocol.prepare_mul(x, y);
}
protocol.exchange();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < reg[4 * i]; j++)
{
proc.S[reg[4 * i + 1] + j] = protocol.finalize_mul();
}
protocol.counter += reg[4 * i];
}
}
template<class T>
void SubProcessor<T>::dotprods(const vector<int>& reg)
{
protocol.init_dotprod(this);
auto it = reg.begin();
while (it != reg.end())
{
auto next = it + *it;
it += 2;
while (it != next)
{
protocol.prepare_dotprod(S[*it], S[*(it + 1)]);
it += 2;
}
protocol.next_dotprod();
}
protocol.exchange();
it = reg.begin();
while (it != reg.end())
{
auto next = it + *it;
it++;
T& dest = S[*it];
dest = protocol.finalize_dotprod((next - it) / 2);
it = next;
}
}
template<class sint, class sgf2n>
ostream& operator<<(ostream& s,const Processor<sint, sgf2n>& P)
{

View File

@@ -3,6 +3,8 @@
#include "Processor/Data_Files.h"
#include "Processor/Processor.h"
#include "Processor/Instruction.hpp"
void Program::compute_constants()
{
for (int reg_type = 0; reg_type < MAX_REG_TYPE; reg_type++)

View File

@@ -30,33 +30,42 @@ public:
Player& P;
ReplicatedBase(Player& P);
int get_n_relevant_players() { return P.num_players() - 1; }
};
template <class T>
class PrepLessProtocol
class ProtocolBase
{
public:
int counter;
public:
PrepLessProtocol();
virtual ~PrepLessProtocol();
ProtocolBase();
virtual ~ProtocolBase();
void muls(const vector<int>& reg, SubProcessor<T>& proc, MAC_Check_Base<T>& MC,
int size);
void mulrs(const vector<int>& reg, SubProcessor<T>& proc);
void dotprods(const vector<int>& reg, SubProcessor<T>& proc);
virtual void init_mul(SubProcessor<T>* proc) = 0;
virtual typename T::clear prepare_mul(const T& x, const T& y) = 0;
virtual void exchange() = 0;
virtual T finalize_mul() = 0;
virtual T get_random() = 0;
void init_dotprod(SubProcessor<T>* proc) { init_mul(proc); }
void prepare_dotprod(const T& x, const T& y) { prepare_mul(x, y); }
void next_dotprod() {}
T finalize_dotprod(int length);
};
template <class T>
class Replicated : public ReplicatedBase, public PrepLessProtocol<T>
class Replicated : public ReplicatedBase, public ProtocolBase<T>
{
vector<octetStream> os;
deque<typename T::clear> add_shares;
typename T::clear dotprod_share;
public:
typedef ReplicatedMC<T> MAC_Check;
typedef ReplicatedInput<T> Input;
@@ -78,6 +87,13 @@ public:
void exchange();
T finalize_mul();
void prepare_reshare(const typename T::clear& share);
void init_dotprod(SubProcessor<T>* proc);
void prepare_dotprod(const T& x, const T& y);
void next_dotprod();
T finalize_dotprod(int length);
T get_random();
};

View File

@@ -13,7 +13,7 @@
#include "GC/ReplicatedSecret.h"
template<class T>
PrepLessProtocol<T>::PrepLessProtocol() : counter(0)
ProtocolBase<T>::ProtocolBase() : counter(0)
{
}
@@ -38,36 +38,42 @@ inline ReplicatedBase::ReplicatedBase(Player& P) : P(P)
}
template<class T>
PrepLessProtocol<T>::~PrepLessProtocol()
ProtocolBase<T>::~ProtocolBase()
{
if (counter)
cerr << "Number of multiplications: " << counter << endl;
}
template<class T>
void PrepLessProtocol<T>::muls(const vector<int>& reg,
void ProtocolBase<T>::muls(const vector<int>& reg,
SubProcessor<T>& proc, MAC_Check_Base<T>& MC, int size)
{
(void)MC;
assert(reg.size() % 3 == 0);
int n = reg.size() / 3;
proc.muls(reg, size);
}
init_mul(&proc);
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
auto& x = proc.S[reg[3 * i + 1] + j];
auto& y = proc.S[reg[3 * i + 2] + j];
prepare_mul(x, y);
}
exchange();
for (int i = 0; i < n; i++)
for (int j = 0; j < size; j++)
{
proc.S[reg[3 * i] + j] = finalize_mul();
}
template<class T>
void ProtocolBase<T>::mulrs(const vector<int>& reg,
SubProcessor<T>& proc)
{
proc.mulrs(reg);
}
counter += n * size;
template<class T>
void ProtocolBase<T>::dotprods(const vector<int>& reg,
SubProcessor<T>& proc)
{
proc.dotprods(reg);
}
template<class T>
T ProtocolBase<T>::finalize_dotprod(int length)
{
counter += length;
T res;
for (int i = 0; i < length; i++)
res += finalize_mul();
return res;
}
template<class T>
@@ -87,28 +93,34 @@ void Replicated<T>::init_mul()
}
template<class T>
typename T::clear Replicated<T>::prepare_mul(const T& x,
inline typename T::clear Replicated<T>::prepare_mul(const T& x,
const T& y)
{
typename T::value_type add_share = x[0] * y.sum() + x[1] * y[0];
typename T::value_type add_share = x.local_mul(y);
prepare_reshare(add_share);
return add_share;
}
template<class T>
inline void Replicated<T>::prepare_reshare(const typename T::clear& share)
{
auto add_share = share;
typename T::value_type tmp[2];
for (int i = 0; i < 2; i++)
tmp[i].randomize(shared_prngs[i]);
add_share += tmp[0] - tmp[1];
add_share.pack(os[0]);
add_shares.push_back(add_share);
return add_share;
}
template<class T>
void Replicated<T>::exchange()
{
P.send_relative(1, os[0]);
P.receive_relative(- 1, os[0]);
P.pass_around(os[0], 1);
}
template<class T>
T Replicated<T>::finalize_mul()
inline T Replicated<T>::finalize_mul()
{
T result;
result[0] = add_shares.front();
@@ -117,6 +129,34 @@ T Replicated<T>::finalize_mul()
return result;
}
template<class T>
inline void Replicated<T>::init_dotprod(SubProcessor<T>* proc)
{
init_mul(proc);
dotprod_share.assign_zero();
}
template<class T>
inline void Replicated<T>::prepare_dotprod(const T& x, const T& y)
{
dotprod_share += x.local_mul(y);
}
template<class T>
inline void Replicated<T>::next_dotprod()
{
prepare_reshare(dotprod_share);
dotprod_share.assign_zero();
}
template<class T>
inline T Replicated<T>::finalize_dotprod(int length)
{
(void) length;
this->counter++;
return finalize_mul();
}
template<class T>
T Replicated<T>::get_random()
{

View File

@@ -21,7 +21,7 @@ void ReplicatedInput<T>::reset(int player)
}
template<class T>
void ReplicatedInput<T>::add_mine(const typename T::clear& input)
inline void ReplicatedInput<T>::add_mine(const typename T::clear& input)
{
auto& shares = this->shares;
shares.push_back({});
@@ -89,7 +89,7 @@ void PrepLessInput<T>::stop(int player, vector<int> targets)
}
template<class T>
void ReplicatedInput<T>::finalize_other(int player, T& target,
inline void ReplicatedInput<T>::finalize_other(int player, T& target,
octetStream& o)
{
typename T::value_type t;

View File

@@ -28,7 +28,7 @@ protected:
virtual void buffer_inverses(MAC_Check_Base<T>& MC, Player& P);
public:
static const int buffer_size = 1000;
static const int buffer_size = 10000;
virtual ~BufferPrep() {}
@@ -49,6 +49,8 @@ protected:
typename T::Protocol* protocol;
SubProcessor<T>* proc;
int base_player;
void buffer_triples();
void buffer_squares();
void buffer_inverses() { throw runtime_error("not inverses in rings"); }
@@ -57,7 +59,7 @@ public:
ReplicatedRingPrep(SubProcessor<T>* proc);
virtual ~ReplicatedRingPrep() {}
void set_protocol(typename T::Protocol& protocol) { this->protocol = &protocol; }
void set_protocol(typename T::Protocol& protocol);
virtual void buffer_bits();
};

View File

@@ -15,6 +15,16 @@ ReplicatedRingPrep<T>::ReplicatedRingPrep(SubProcessor<T>* proc) :
{
}
template<class T>
void ReplicatedRingPrep<T>::set_protocol(typename T::Protocol& protocol)
{
this->protocol = &protocol;
if (proc)
base_player = proc->Proc.thread_num;
else
base_player = 0;
}
template<class T>
void ReplicatedRingPrep<T>::buffer_triples()
{
@@ -90,7 +100,7 @@ void BufferPrep<T>::buffer_inverses(MAC_Check_Base<T>& MC, Player& P)
MC.POpen(c_open, c, P);
for (size_t i = 0; i < c.size(); i++)
if (c_open[i] != 0)
inverses.push_back({triples[i][0], triples[i][1] / c_open[i]});
inverses.push_back({{triples[i][0], triples[i][1] / c_open[i]}});
triples.clear();
if (inverses.empty())
throw runtime_error("products were all zero");
@@ -141,25 +151,12 @@ void XOR(vector<T>& res, vector<T>& x, vector<T>& y, int buffer_size,
res[i] = x[i] + y[i] - prot.finalize_mul() * two;
}
int get_n_relevant_players(Player& P)
{
int n_relevant_players = P.num_players();
try
{
n_relevant_players = ShamirMachine::s().threshold + 1;
}
catch (...)
{
}
return n_relevant_players;
}
template<template<class U> class T>
void buffer_bits_spec(ReplicatedPrep<T<gfp>>& prep, vector<T<gfp>>& bits,
typename T<gfp>::Protocol& prot)
{
(void) bits, (void) prot;
if (get_n_relevant_players(prot.P) > 10)
if (prot.get_n_relevant_players() > 10)
{
vector<array<T<gfp>, 2>> squares(prep.buffer_size);
vector<T<gfp>> s;
@@ -189,12 +186,12 @@ void ReplicatedRingPrep<T>::buffer_bits()
auto buffer_size = this->buffer_size;
auto& bits = this->bits;
auto& P = protocol->P;
int n_relevant_players = get_n_relevant_players(P);
int n_relevant_players = protocol->get_n_relevant_players();
vector<vector<T>> player_bits(n_relevant_players, vector<T>(buffer_size));
typename T::Input input(proc, P);
for (int i = 0; i < n_relevant_players; i++)
for (int i = 0; i < P.num_players(); i++)
input.reset(i);
if (P.my_num() < n_relevant_players)
if (positive_modulo(P.my_num() - base_player, P.num_players()) < n_relevant_players)
{
SeededPRNG G;
for (int i = 0; i < buffer_size; i++)
@@ -202,25 +199,28 @@ void ReplicatedRingPrep<T>::buffer_bits()
input.send_mine();
}
for (int i = 0; i < n_relevant_players; i++)
if (i == P.my_num())
{
int input_player = (base_player + i) % P.num_players();
if (input_player == P.my_num())
for (auto& x : player_bits[i])
x = input.finalize_mine();
else
{
octetStream os;
P.receive_player(i, os, true);
P.receive_player(input_player, os, true);
for (auto& x : player_bits[i])
input.finalize_other(i, x, os);
input.finalize_other(input_player, x, os);
}
}
auto& prot = *protocol;
vector<T> tmp;
XOR(tmp, player_bits[0], player_bits[1], buffer_size, prot, proc);
for (int i = 2; i < n_relevant_players - 1; i++)
XOR(tmp, tmp, player_bits[i], buffer_size, prot, proc);
XOR(bits, tmp, player_bits[n_relevant_players - 1], buffer_size, prot, proc);
XOR(bits, player_bits[0], player_bits[1], buffer_size, prot, proc);
for (int i = 2; i < n_relevant_players; i++)
XOR(bits, bits, player_bits[i], buffer_size, prot, proc);
base_player++;
}
template<>
inline
void ReplicatedRingPrep<Rep3Share<gf2n>>::buffer_bits()
{
assert(protocol != 0);

View File

@@ -1,14 +0,0 @@
/*
* Multiplication.cpp
*
*/
#include "SPDZ.h"
#include "Processor.h"
#include "Math/Share.h"
#include "Auth/MAC_Check.h"
#include "Input.hpp"
template class SPDZ<gfp>;
template class SPDZ<gf2n>;

View File

@@ -19,7 +19,7 @@ template<class T> class ShamirInput;
class Player;
template<class U>
class Shamir : public PrepLessProtocol<ShamirShare<U>>
class Shamir : public ProtocolBase<ShamirShare<U>>
{
typedef ShamirShare<U> T;
@@ -45,6 +45,8 @@ public:
Shamir(Player& P);
~Shamir();
int get_n_relevant_players();
void reset();
void init_mul(SubProcessor<T>* proc);

View File

@@ -5,7 +5,7 @@
#include "Shamir.h"
#include "ShamirInput.h"
#include "ShamirMachine.h"
#include "Machines/ShamirMachine.h"
template<class U>
U Shamir<U>::get_rec_factor(int i, int n)
@@ -31,6 +31,12 @@ Shamir<U>::~Shamir()
delete resharing;
}
template<class U>
int Shamir<U>::get_n_relevant_players()
{
return ShamirMachine::s().threshold + 1;
}
template<class U>
void Shamir<U>::reset()
{

View File

@@ -4,7 +4,7 @@
*/
#include "ShamirInput.h"
#include "ShamirMachine.h"
#include "Machines/ShamirMachine.h"
template<class U>
void ShamirInput<U>::reset(int player)

View File

@@ -117,3 +117,17 @@ print_ln('weighted average: %s', result.reveal())
print_ln_if((sum(point[0] for point in data) == 0).reveal(), \
'but the inputs were invalid (weights add up to zero)')
# permutation matrix
M = Matrix(2, 2, sfix)
M[0][0] = 0
M[1][0] = 1
M[0][1] = 1
M[1][1] = 0
# matrix multiplication
M = data * M
test(M[0][0], data[0][1].reveal())
test(M[1][1], data[1][0].reveal())

View File

@@ -5,16 +5,40 @@ protocols such as SPDZ, MASCOT, Overdrive, BMR garbled circuits
(evaluation only), Yao's garbled circuits, and computation based on
semi-honest three-party replicated secret sharing (with an honest majority).
#### TL;DR
#### TL;DR (Binary Distribution on Linux or Souce Distribution on macOS)
This requires `sudo` rights as well as a working toolchain installed
for the first step, refer to [the requirements](#requirements)
otherwise. It will execute [the
This requires either a Linux distribution originally released 2011 or
later (glibc 2.12) or macOS High Sierra or later as well as Python 2
and basic command-line utilities.
Download and unpack the distribution, then execute the following from
the top folder:
```
Scripts/tldr.sh
./compile.py tutorial
echo 1 2 3 > Player-Data/Input-P0-0
echo 1 2 3 > Player-Data/Input-P1-0
Scripts/mal-rep-field.sh tutorial
```
This runs [the tutorial](Programs/Source/tutorial.mpc) with three
parties, an honest majority, and malicious security.
#### TL;DR (Source Distribution)
On Linux, this requires a working toolchain and [all
requirements](#requirements). On Ubuntu, the following might suffice:
```
apt-get install automake build-essential git libboost-dev libboost-thread-dev libsodium-dev libssl-dev libtool m4 python texinfo yasm
```
On MacOS, this requires [brew](https://brew.sh) to be installed,
which will be used for all dependencies.
It will execute [the
tutorial](Programs/Source/tutorial.mpc) with three
parties, an honest majority, and malicious security.
```
make -j 8 mpir
make -j 8 tldr
./compile.py tutorial
Scripts/setup-replicated.sh
@@ -95,10 +119,10 @@ phase outputs the amount of offline material required, which allows to
compute the preprocessing time for a particulor computation.
#### Requirements
- GCC 4.8 or later (tested with 7.3; remove `-no-pie` from `CONFIG` for GCC 4.8) or LLVM (tested with 6.0; remove `-no-pie` from `CONFIG`)
- GCC 4.8 or later (tested with 7.3) or LLVM (tested with 6.0)
- MPIR library, compiled with C++ support (use flag --enable-cxx when running configure)
- libsodium library, tested against 1.0.16
- OpenSSL, tested against 1.1.0
- OpenSSL, tested against and 1.0.2 and 1.1.0
- Boost.Asio with SSL support (`libboost-dev` on Ubuntu), tested against 1.65
- Boost.Thread for BMR (`libboost-thread-dev` on Ubuntu), tested against 1.65
- CPU supporting AES-NI, PCLMUL, AVX2

20
Scripts/build.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
function build
{
echo ARCH = $1 >> CONFIG.mine
echo GDEBUG = >> CONFIG.mine
make clean
rm -R static
mkdir static
make -j 12 static-hm
mkdir bin
dest=bin/`uname`-$2
rm -R $dest
mv static $dest
strip $dest/*
}
build '' amd64
build '-msse4.1 -maes -mpclmul' aes
build '-msse4.1 -maes -mpclmul -mavx -mavx2 -mbmi2' avx2

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <fstream>
#include "Math/gf2n.h"
#include "Processor/Buffer.h"
#include "Tools/Buffer.h"
using namespace std;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <fstream>
#include "Math/gfp.h"
#include "Processor/Buffer.h"
#include "Tools/Buffer.h"
#include "Tools/ezOptionParser.h"
#include "Math/Setup.h"

View File

@@ -54,4 +54,4 @@ SPDZROOT=${SPDZROOT:-.}
#. Scripts/setup.sh
mkdir logs
mkdir logs 2> /dev/null

View File

@@ -32,6 +32,3 @@ $HERE/setup-ssl.sh ${players}
$SPDZROOT/Fake-Offline.x ${players} -lgp ${bits} -lg2 ${g} --default ${default}
for i in $(seq 0 $[players-1]) ; do
dd if=/dev/zero of=Player-Data/Private-Input-$i bs=10000 count=1
done

View File

@@ -10,4 +10,6 @@ for i in `seq 0 $[n-1]`; do
openssl req -newkey rsa -nodes -x509 -out Player-Data/P$i.pem -keyout Player-Data/P$i.key -subj "/CN=P$i"
done
# brew-installed OpenSSL on MacOS
PATH=$PATH:/usr/local/opt/openssl/bin/
c_rehash Player-Data

35
Scripts/tldr.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/sh
if test `uname` = "Linux"; then
flags='cat /proc/cpuinfo'
elif test `uname` = Darwin; then
if ! type brew; then
echo Do you want me to install Homebrew?
echo Press RETURN to continue or any other key to abort
read ans
if test "$ans"; then
echo Aborting
exit 1
else
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi
fi
make tldr
else
echo OS unknown
exit 1
fi
if test "$flags"; then
if $flags | grep -q avx2; then
cpu=avx2
elif $flags | grep -q aes; then
cpu=aes
else
cpu=amd64
fi
cp -av bin/`uname`-$cpu/* .
fi
Scripts/setup-ssl.sh

View File

@@ -3,7 +3,7 @@
*
*/
#include "Buffer.h"
#include "Tools/Buffer.h"
bool BufferBase::rewind = false;

View File

@@ -3,8 +3,8 @@
*
*/
#ifndef PROCESSOR_BUFFER_H_
#define PROCESSOR_BUFFER_H_
#ifndef TOOLS_BUFFER_H_
#define TOOLS_BUFFER_H_
#include <fstream>
using namespace std;
@@ -12,7 +12,7 @@ using namespace std;
#include "Math/Share.h"
#include "Math/field_types.h"
#include "Tools/time-func.h"
#include "config.h"
#include "Processor/config.h"
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 101
@@ -153,4 +153,4 @@ inline void Buffer<T,U>::input(U& a)
next++;
}
#endif /* PROCESSOR_BUFFER_H_ */
#endif /* TOOLS_BUFFER_H_ */

View File

@@ -35,6 +35,7 @@ void aes_128_schedule( octet* key, const octet* userkey )
__m128i *Key_Schedule = (__m128i*)key;
temp1 = _mm_loadu_si128((__m128i*)userkey);
Key_Schedule[0] = temp1;
#ifdef __AES__
temp2 = _mm_aeskeygenassist_si128 (temp1 ,0x1);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[1] = temp1;
@@ -65,8 +66,13 @@ void aes_128_schedule( octet* key, const octet* userkey )
temp2 = _mm_aeskeygenassist_si128 (temp1,0x36);
temp1 = AES_128_ASSIST(temp1, temp2);
Key_Schedule[10] = temp1;
#else
(void) temp2;
throw runtime_error("need to compile with AES-NI support");
#endif
}
#ifdef __AES__
inline void KEY_192_ASSIST(__m128i* temp1, __m128i * temp2, __m128i * temp3)
{ __m128i temp4;
*temp2 = _mm_shuffle_epi32 (*temp2, 0x55);
@@ -222,7 +228,7 @@ void aes_256_encrypt(octet* out, const octet* in, const octet* key)
tmp = _mm_aesenclast_si128 (tmp,((__m128i*)key)[j]);
_mm_storeu_si128 (&((__m128i*)out)[0],tmp);
}
#endif

View File

@@ -54,10 +54,14 @@ __attribute__((optimize("unroll-loops")))
inline __m128i aes_128_encrypt(__m128i in, const octet* key)
{ __m128i& tmp = in;
tmp = _mm_xor_si128 (tmp,((__m128i*)key)[0]);
#ifdef __AES__
int j;
for(j=1; j <10; j++)
{ tmp = _mm_aesenc_si128 (tmp,((__m128i*)key)[j]); }
tmp = _mm_aesenclast_si128 (tmp,((__m128i*)key)[j]);
#else
throw runtime_error("need to compile with AES-NI support");
#endif
return tmp;
}
@@ -70,12 +74,17 @@ inline void ecb_aes_128_encrypt(__m128i* out, __m128i* in, const octet* key)
__m128i tmp[N];
for (int i = 0; i < N; i++)
tmp[i] = _mm_xor_si128 (in[i],((__m128i*)key)[0]);
#ifdef __AES__
int j;
for(j=1; j <10; j++)
for (int i = 0; i < N; i++)
tmp[i] = _mm_aesenc_si128 (tmp[i],((__m128i*)key)[j]);
for (int i = 0; i < N; i++)
out[i] = _mm_aesenclast_si128 (tmp[i],((__m128i*)key)[j]);
#else
(void) tmp, (void) out;
throw runtime_error("need to compile with AES-NI support");
#endif
}
template <int N>

View File

@@ -201,8 +201,7 @@ void octetStream::exchange(T send_socket, T receive_socket, octetStream& receive
if (sent < len)
{
size_t to_send = min(buffer_size, len - sent);
send(send_socket, data + sent, to_send);
sent += to_send;
sent += send_non_blocking(send_socket, data + sent, to_send);
}
// avoid extra branching, false before length received

View File

@@ -10,10 +10,11 @@ using namespace std;
PRNG::PRNG() : cnt(0)
{
#ifdef __AES__
#ifdef USE_AES
useC=(Check_CPU_support_AES()==0);
#endif
#endif
}
void PRNG::ReSeed()

View File

@@ -16,7 +16,11 @@
#define SEED_SIZE HASH_SIZE
#define RAND_SIZE HASH_SIZE
#else
#ifdef __AES__
#define PIPELINES 8
#else
#define PIPELINES 1
#endif
#define SEED_SIZE AES_BLK_SIZE
#define RAND_SIZE (PIPELINES * AES_BLK_SIZE)
#endif
@@ -38,7 +42,11 @@ class PRNG
octet random[RAND_SIZE] __attribute__((aligned (16)));
#ifdef USE_AES
#ifdef __AES__
bool useC;
#else
const static bool useC = true;
#endif
// Two types of key schedule for the different implementations
// of AES

View File

@@ -9,6 +9,8 @@
#include "GC/Instruction.hpp"
#include "GC/Program.hpp"
#include "Processor/Instruction.hpp"
namespace GC
{

View File

@@ -15,7 +15,8 @@
#include "GC/Secret.h"
#include "Networking/Player.h"
#include "OT/OTExtensionWithMatrix.h"
#include "sys/sysinfo.h"
#include <thread>
using namespace GC;
@@ -66,7 +67,8 @@ public:
const Key& get_delta() { return master.delta; }
void store_gate(const YaoGate& gate);
int get_n_worker_threads() { return max(1, get_nprocs() / master.machine.nthreads); }
int get_n_worker_threads()
{ return max(1u, thread::hardware_concurrency() / master.machine.nthreads); }
int get_threshold() { return master.threshold; }
long get_gate_id() { return gate_id(thread_num); }

Some files were not shown because too many files have changed in this diff Show More