From b6a18675e86d05940f871cc6bcb1cec4bedfb606 Mon Sep 17 00:00:00 2001 From: Marcel Keller Date: Thu, 14 Feb 2019 15:15:37 +1100 Subject: [PATCH] Optimized matrix multiplication; data type for quantization. --- .gitignore | 1 + Auth/MAC_Check.cpp | 2 + Auth/MaliciousRepMC.hpp | 5 +- Auth/MaliciousShamirMC.hpp | 2 +- Auth/ShamirMC.h | 2 +- BMR/AuthValue.cpp | 5 + BMR/Key.h | 11 +- BMR/Party.h | 4 +- BMR/Program.cpp | 2 + BMR/aes.cpp | 200 +---- BMR/aes.h | 31 - BMR/network/Server.cpp | 2 +- BMR/prf.cpp | 21 - BMR/prf.h | 9 - CHANGELOG.md | 6 + CONFIG | 18 +- Check-Offline.cpp | 1 + Compiler/GC/types.py | 76 +- Compiler/allocator.py | 4 +- Compiler/comparison.py | 67 +- Compiler/floatingpoint.py | 44 +- Compiler/instructions.py | 79 +- Compiler/instructions_base.py | 42 +- Compiler/library.py | 5 +- Compiler/program.py | 43 +- Compiler/types.py | 756 ++++++++++++++---- Compiler/util.py | 23 +- FHEOffline/SimpleEncCommit.cpp | 2 + Fake-Offline.cpp | 1 + GC/Machine.cpp | 5 +- GC/MaliciousRepThread.cpp | 3 +- GC/square64.cpp | 15 +- Machines/Rep.cpp | 49 ++ Machines/SPDZ.cpp | 6 + {Processor => Machines}/ShamirMachine.cpp | 41 +- {Processor => Machines}/ShamirMachine.h | 6 +- Makefile | 78 +- Math/BitVec.h | 2 + Math/Integer.h | 4 +- Math/Rep3Share.h | 5 + Math/Zp_Data.h | 4 + Math/field_types.h | 3 +- Math/gf2n.cpp | 8 + Math/gf2n.h | 2 + Math/gf2nlong.h | 13 +- Math/gfp.cpp | 12 + Math/gfp.h | 6 +- Math/mpn_fixed.h | 2 + Math/operators.h | 4 +- Networking/CryptoPlayer.cpp | 1 + Networking/Player.cpp | 14 +- Networking/Player.h | 6 +- Networking/sockets.cpp | 2 +- Networking/sockets.h | 19 +- Networking/ssl_sockets.h | 7 +- OT/BitMatrix.cpp | 3 +- OT/BitVector.h | 2 +- Player-Online.cpp | 12 +- Processor/BaseMachine.cpp | 94 +++ Processor/Beaver.h | 20 +- Processor/Beaver.hpp | 68 +- Processor/Data_Files.h | 6 +- Processor/{Data_Files.cpp => Data_Files.hpp} | 159 +--- Processor/Input.h | 2 +- Processor/Instruction.h | 4 + .../{Instruction.cpp => Instruction.hpp} | 70 +- Processor/Machine.h | 3 + Processor/{Machine.cpp => Machine.hpp} | 105 +-- Processor/MaliciousRepPrep.hpp | 18 +- Processor/Online-Thread.hpp | 2 + Processor/Processor.h | 6 +- Processor/Processor.hpp | 81 +- Processor/Program.cpp | 2 + Processor/Replicated.h | 28 +- Processor/Replicated.hpp | 92 ++- Processor/ReplicatedInput.hpp | 4 +- Processor/ReplicatedPrep.h | 6 +- Processor/ReplicatedPrep.hpp | 52 +- Processor/SPDZ.cpp | 14 - Processor/Shamir.h | 4 +- Processor/Shamir.hpp | 8 +- Processor/ShamirInput.hpp | 2 +- Programs/Source/tutorial.mpc | 14 + README.md | 38 +- Scripts/build.sh | 20 + Scripts/gen_input_f2n.cpp | 2 +- Scripts/gen_input_fp.cpp | 2 +- Scripts/run-common.sh | 2 +- Scripts/setup-online.sh | 3 - Scripts/setup-ssl.sh | 2 + Scripts/tldr.sh | 35 + {Processor => Tools}/Buffer.cpp | 2 +- {Processor => Tools}/Buffer.h | 8 +- Tools/aes-ni.cpp | 8 +- Tools/aes.h | 9 + Tools/octetStream.cpp | 3 +- Tools/random.cpp | 3 +- Tools/random.h | 8 + Yao/Program.cpp | 2 + Yao/YaoGarbler.h | 6 +- bin/README.md | 13 + bin/boost-license.txt | 23 + bin/glibc-license.txt | 502 ++++++++++++ bin/libsodium-license.txt | 18 + bin/mpir-license.txt | 165 ++++ bin/openssl-license.txt | 125 +++ malicious-shamir-party.cpp | 2 +- shamir-party.cpp | 2 +- 108 files changed, 2671 insertions(+), 994 deletions(-) delete mode 100644 BMR/prf.cpp create mode 100644 Machines/Rep.cpp create mode 100644 Machines/SPDZ.cpp rename {Processor => Machines}/ShamirMachine.cpp (60%) rename {Processor => Machines}/ShamirMachine.h (79%) create mode 100644 Processor/BaseMachine.cpp rename Processor/{Data_Files.cpp => Data_Files.hpp} (64%) rename Processor/{Instruction.cpp => Instruction.hpp} (97%) rename Processor/{Machine.cpp => Machine.hpp} (79%) delete mode 100644 Processor/SPDZ.cpp create mode 100755 Scripts/build.sh create mode 100755 Scripts/tldr.sh rename {Processor => Tools}/Buffer.cpp (98%) rename {Processor => Tools}/Buffer.h (96%) create mode 100644 bin/README.md create mode 100644 bin/boost-license.txt create mode 100644 bin/glibc-license.txt create mode 100644 bin/libsodium-license.txt create mode 100644 bin/mpir-license.txt create mode 100644 bin/openssl-license.txt diff --git a/.gitignore b/.gitignore index d7d3a32..56bffa6 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ Programs/Public-Input/* *.a *.static *.d +local/ # Packages # ############ diff --git a/Auth/MAC_Check.cpp b/Auth/MAC_Check.cpp index c2eeee8..5a7cb50 100644 --- a/Auth/MAC_Check.cpp +++ b/Auth/MAC_Check.cpp @@ -466,3 +466,5 @@ template class MAC_Check_Base>; template class MAC_Check_Base>; template class MAC_Check_Base>; template class MAC_Check_Base>; +template class MAC_Check_Base>; +template class MAC_Check_Base>; diff --git a/Auth/MaliciousRepMC.hpp b/Auth/MaliciousRepMC.hpp index 81709ca..6b0cad1 100644 --- a/Auth/MaliciousRepMC.hpp +++ b/Auth/MaliciousRepMC.hpp @@ -85,14 +85,15 @@ void CommMaliciousRepMC::POpen_Begin(vector& 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 void CommMaliciousRepMC::POpen_End(vector& values, const vector& S, const Player& P) { - P.receive_relative(os); + (void) P; if (os[0] != os[1]) throw mac_fail(); values.clear(); diff --git a/Auth/MaliciousShamirMC.hpp b/Auth/MaliciousShamirMC.hpp index 457a67b..98691b9 100644 --- a/Auth/MaliciousShamirMC.hpp +++ b/Auth/MaliciousShamirMC.hpp @@ -4,7 +4,7 @@ */ #include "MaliciousShamirMC.h" -#include "Processor/ShamirMachine.h" +#include "Machines/ShamirMachine.h" template MaliciousShamirMC::MaliciousShamirMC() diff --git a/Auth/ShamirMC.h b/Auth/ShamirMC.h index a0f1bc2..431bd51 100644 --- a/Auth/ShamirMC.h +++ b/Auth/ShamirMC.h @@ -8,7 +8,7 @@ #include "MAC_Check.h" #include "Math/ShamirShare.h" -#include "Processor/ShamirMachine.h" +#include "Machines/ShamirMachine.h" template class ShamirMC : public MAC_Check_Base diff --git a/BMR/AuthValue.cpp b/BMR/AuthValue.cpp index 7c74a94..376f021 100644 --- a/BMR/AuthValue.cpp +++ b/BMR/AuthValue.cpp @@ -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) diff --git a/BMR/Key.h b/BMR/Key.h index 15ebbac..b902f1d 100644 --- a/BMR/Key.h +++ b/BMR/Key.h @@ -12,6 +12,7 @@ #include #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 } diff --git a/BMR/Party.h b/BMR/Party.h index ac04041..a0a7012 100644 --- a/BMR/Party.h +++ b/BMR/Party.h @@ -8,7 +8,7 @@ #include #include -#include +#include #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 diff --git a/BMR/Program.cpp b/BMR/Program.cpp index 79cee99..25c1b73 100644 --- a/BMR/Program.cpp +++ b/BMR/Program.cpp @@ -9,6 +9,8 @@ #include "GC/Instruction.hpp" #include "GC/Program.hpp" +#include "Processor/Instruction.hpp" + namespace GC { diff --git a/BMR/aes.cpp b/BMR/aes.cpp index 3cf01bc..19bb353 100644 --- a/BMR/aes.cpp +++ b/BMR/aes.cpp @@ -1,4 +1,5 @@ #include "aes.h" +#include #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; jrd_key)); - - *blk = _mm_xor_si128(*blk, sched[0]); - for (j = 1; jrd_key)); - for (i=0; ird_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 } diff --git a/BMR/aes.h b/BMR/aes.h index 993a917..14ac3f4 100644 --- a/BMR/aes.h +++ b/BMR/aes.h @@ -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_ */ diff --git a/BMR/network/Server.cpp b/BMR/network/Server.cpp index 1f1ccf6..3ced867 100644 --- a/BMR/network/Server.cpp +++ b/BMR/network/Server.cpp @@ -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)) diff --git a/BMR/prf.cpp b/BMR/prf.cpp deleted file mode 100644 index 64dfe43..0000000 --- a/BMR/prf.cpp +++ /dev/null @@ -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); -} diff --git a/BMR/prf.h b/BMR/prf.h index 1054e0b..1240347 100644 --- a/BMR/prf.h +++ b/BMR/prf.h @@ -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; diff --git a/CHANGELOG.md b/CHANGELOG.md index 0139007..2e5ed50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CONFIG b/CONFIG index c67996b..5d675c6 100644 --- a/CONFIG +++ b/CONFIG @@ -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= 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) diff --git a/Check-Offline.cpp b/Check-Offline.cpp index 1f0ec91..5ad3010 100644 --- a/Check-Offline.cpp +++ b/Check-Offline.cpp @@ -14,6 +14,7 @@ #include "Processor/Data_Files.h" #include "Auth/fake-stuff.hpp" +#include "Processor/Data_Files.hpp" #include #include diff --git a/Compiler/GC/types.py b/Compiler/GC/types.py index 9258c38..5be7ab2 100644 --- a/Compiler/GC/types.py +++ b/Compiler/GC/types.py @@ -6,11 +6,10 @@ 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 @@ def malloc(cls, size): 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 @@ def if_else(self, x, y): 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 @@ def __len__(self): @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, sbits_type): 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 @@ def bit_compose(cls, bits): 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 @@ def TruncMul(self, other, k, m, kappa=None): (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 @@ def extend(self, n): 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 @@ def __mul__(self, other): __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 diff --git a/Compiler/allocator.py b/Compiler/allocator.py index 7dbb92c..7318a87 100644 --- a/Compiler/allocator.py +++ b/Compiler/allocator.py @@ -43,8 +43,7 @@ def alloc_reg(self, reg, free): 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 @@ def dealloc_reg(self, reg, inst, free): 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: diff --git a/Compiler/comparison.py b/Compiler/comparison.py index c3494dc..b972ef8 100644 --- a/Compiler/comparison.py +++ b/Compiler/comparison.py @@ -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() + if signed: + a += (1 << (k - 1)) + 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) + u = sint() + BitLTL(u, masked, r_bits, 0) + res = (u << n_bits) + masked - r if signed: - res = sint.conv(res_bits[-1].if_else(res - (sint(1) << n_bits), - res)) + 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): """ diff --git a/Compiler/floatingpoint.py b/Compiler/floatingpoint.py index e2e204f..816ea98 100644 --- a/Compiler/floatingpoint.py +++ b/Compiler/floatingpoint.py @@ -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): diff --git a/Compiler/instructions.py b/Compiler/instructions.py index 18a0712..2c65dd0 100644 --- a/Compiler/instructions.py +++ b/Compiler/instructions.py @@ -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 @@ def get_repeat(self): # 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 ### diff --git a/Compiler/instructions_base.py b/Compiler/instructions_base.py index dde5c3a..b2a7a85 100644 --- a/Compiler/instructions_base.py +++ b/Compiler/instructions_base.py @@ -87,6 +87,8 @@ # 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 expand(self): @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 reformat(arg_format): 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) diff --git a/Compiler/library.py b/Compiler/library.py index 01577bb..7e46c15 100644 --- a/Compiler/library.py +++ b/Compiler/library.py @@ -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 diff --git a/Compiler/program.py b/Compiler/program.py index c657e4d..d6db92b 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -68,6 +68,10 @@ def __init__(self, args, options, param=-1, assemblymode=False): 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 @@ def __init__(self, parent, name, scope, exit_condition=None): 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 @@ def adjust_jump(self): 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 @@ def init_names(self, name): 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 @@ def __init__(self, name): 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 @@ def __init__(self, reg_type, program, value=None, size=None, i=None): 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 @@ def set_size(self, size): 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() diff --git a/Compiler/types.py b/Compiler/types.py index 6f12e22..2667ed5 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -58,6 +58,20 @@ def vectorized_operation(self, *args, **kwargs): return res return vectorized_operation +def vectorize_max(operation): + def vectorized_operation(self, *args, **kwargs): + size = self.size + for arg in args: + try: + size = max(size, arg.size) + except AttributeError: + pass + set_global_vector_size(size) + res = operation(self, *args, **kwargs) + reset_global_vector_size() + return res + return vectorized_operation + def vectorized_classmethod(function): def vectorized_function(cls, *args, **kwargs): size = None @@ -101,10 +115,10 @@ def instruction_typed_operation(self, *args, **kwargs): return instruction_typed_operation def read_mem_value(operation): - def read_mem_operation(self, other, *args, **kwargs): - if isinstance(other, _mem): - other = other.read() - return operation(self, other, *args, **kwargs) + def read_mem_operation(self, *args, **kwargs): + if len(args) > 0 and isinstance(args[0], MemValue): + args = (args[0].read(),) + args[1:] + return operation(self, *args, **kwargs) return read_mem_operation @@ -144,9 +158,22 @@ def __pow__(self, exp): else: return NotImplemented + def mul_no_reduce(self, other, res_params=None): + return self * other + + def reduce_after_mul(self): + return self + + def pow2(self, bit_length=None, security=None): + return 2**self + class _int(object): def if_else(self, a, b): - return self * (a - b) + b + if hasattr(a, 'for_mux'): + f, a, b = a.for_mux(b) + else: + f = lambda x: x + return f(self * (a - b) + b) def cond_swap(self, a, b): prod = self * (a - b) @@ -181,6 +208,12 @@ def Array(cls, size, *args, **kwargs): def Matrix(cls, rows, columns, *args, **kwargs): return Matrix(rows, columns, cls, *args, **kwargs) + @classmethod + def row_matrix_mul(cls, row, matrix, res_params=None): + return sum(row[k].mul_no_reduce(matrix[k].get_vector(), + res_params) \ + for k in range(len(row))).reduce_after_mul() + class _register(Tape.Register, _number, _structure): @staticmethod def n_elements(): @@ -221,16 +254,27 @@ def hard_conv(cls, val): def _load_mem(cls, address, direct_inst, indirect_inst): res = cls() if isinstance(address, _register): - indirect_inst(res, regint.conv(address)) + indirect_inst(res, cls._expand_address(address, + get_global_vector_size())) else: direct_inst(res, address) return res + @staticmethod + def _expand_address(address, size): + address = regint.conv(address) + if size > 1 and address.size == 1: + res = regint(size=size) + for i in range(size): + movint(res[i], address + regint(i, size=1)) + return res + else: + return address + @set_instruction_type - @vectorize def _store_in_mem(self, address, direct_inst, indirect_inst): if isinstance(address, _register): - indirect_inst(self, regint.conv(address)) + indirect_inst(self, self._expand_address(address, self.size)) else: direct_inst(self, address) @@ -259,6 +303,16 @@ def sizeof(self): def extend(self, n): return self + def expand_to_vector(self, size=None): + if size is None: + size = get_global_vector_size() + if self.size == size: + return self + assert self.size == 1 + res = type(self)(size=size) + for i in range(size): + movs(res[i], self) + return res class _clear(_register): __slots__ = [] @@ -509,9 +563,6 @@ def right_shift(self, other, bit_length=None): def greater_than(self, other, bit_length=None): return self > other - def pow2(self, bit_length=None): - return 2**self - def bit_decompose(self, bit_length=None): if bit_length == 0: return [] @@ -890,6 +941,37 @@ def get_random_input_mask_for(cls, player): inputmask(res, player) return res + @classmethod + @set_instruction_type + def dot_product(cls, x, y): + res = cls() + dotprods(res, x, y) + return res + + @classmethod + @set_instruction_type + def row_matrix_mul(cls, row, matrix, res_params=None): + assert len(row) == len(matrix) + size = len(matrix[0]) + res = cls(size=size) + dotprods(*sum(([res[j], row, [matrix[k][j] for k in range(len(row))]] + for j in range(size)), [])) + return res + + @classmethod + @set_instruction_type + def matrix_mul(cls, A, B, n, res_params=None): + assert len(A) % n == 0 + assert len(B) % n == 0 + size = len(A) * len(B) / n**2 + res = cls(size=size) + n_rows = len(A) / n + n_cols = len(B) / n + dotprods(*sum(([res[j], [A[j / n_cols * n + k] for k in range(n)], + [B[k * n_cols + j % n_cols] for k in range(n)]] + for j in range(size)), [])) + return res + def __init__(self, reg_type, val=None, size=None): if isinstance(val, self.clear_type): size = val.size @@ -918,6 +1000,12 @@ def load_other(self, val): else: self.load_clear(self.clear_type(val)) + def _new_by_number(self, i): + res = type(self)(size=1) + res.i = i + res.program = self.program + return res + @set_instruction_type @read_mem_value @vectorize @@ -948,7 +1036,14 @@ def secret_op(self, other, s_inst, m_inst, si_inst, reverse=False): def add(self, other): return self.secret_op(other, adds, addm, addsi) + @set_instruction_type def mul(self, other): + if isinstance(other, _secret) and max(self.size, other.size) > 1 \ + and min(self.size, other.size) == 1: + x, y = (other, self) if self.size < other.size else (self, other) + res = type(self)(size=x.size) + mulrs(res, x, y) + return res return self.secret_op(other, muls, mulm, mulsi) def __sub__(self, other): @@ -1145,12 +1240,13 @@ def __rpow__(self, base): else: return NotImplemented + @vectorize def pow2(self, bit_length=None, security=None): return floatingpoint.Pow2(self, bit_length or program.bit_length, \ security or program.security) - def __lshift__(self, other): - return self * 2**other + def __lshift__(self, other, bit_length=None, security=None): + return self * util.pow2_value(other, bit_length, security) @vectorize @read_mem_value @@ -1168,6 +1264,7 @@ def __rshift__(self, other, bit_length=None, security=None): else: return floatingpoint.Trunc(self, bit_length, sint(other), security) + left_shift = __lshift__ right_shift = __rshift__ def __rlshift__(self, other): @@ -1184,12 +1281,24 @@ def bit_decompose(self, bit_length=None, security=None): security = security or program.security return floatingpoint.BitDec(self, bit_length, bit_length, security) - def TruncMul(self, other, k, m, kappa=None): - return floatingpoint.TruncPr(self * other, k, m, kappa) + def TruncMul(self, other, k, m, kappa=None, nearest=False): + return (self * other).round(k, m, kappa, nearest) def TruncPr(self, k, m, kappa=None): return floatingpoint.TruncPr(self, k, m, kappa) + @vectorize + def round(self, k, m, kappa=None, nearest=False): + secret = isinstance(m, sint) + if nearest: + if secret: + raise NotImplementedError() + return comparison.TruncRoundNearest(self, k, m, kappa) + else: + if secret: + return floatingpoint.Trunc(self, k, m, kappa) + return self.TruncPr(k, m, kappa) + def Norm(self, k, f, kappa=None, simplex_flag=False): return library.Norm(self, k, f, kappa, simplex_flag) @@ -1317,6 +1426,7 @@ def bit_decompose_embedding(self): class _bitint(object): bits = None log_rounds = False + linear_rounds = False @classmethod def bit_adder(cls, a, b): @@ -1329,6 +1439,8 @@ def bit_adder(cls, a, b): def bit_adder_selection(cls, a, b): if cls.log_rounds: return cls.carry_lookahead_adder(a, b) + elif cls.linear_rounds: + return cls.ripple_carry_adder(a, b) else: return cls.carry_select_adder(a, b) @@ -1464,13 +1576,20 @@ def mul(self, other): raise NotImplementedError('Multiplication of different lengths') except AttributeError: pass - other = self.bin_type(other) + try: + other = self.bin_type(other) + except CompilerError: + return NotImplemented products = [x * other for x in self_bits] bit_matrix = [util.bit_decompose(x, self.n_bits) for x in products] + return self.compose(self.wallace_tree_from_matrix(bit_matrix, False)) + + @classmethod + def wallace_tree_from_matrix(cls, bit_matrix, get_carry=True): columns = [filter(None, (bit_matrix[j][i-j] \ for j in range(min(len(bit_matrix), i + 1)))) \ for i in range(len(bit_matrix[0]))] - return self.compose(self.wallace_tree_from_columns(columns, False)) + return cls.wallace_tree_from_columns(columns, get_carry) @classmethod def wallace_tree_from_columns(cls, columns, get_carry=True): @@ -1610,8 +1729,10 @@ def sum_from_carries(a, b, carries): @classmethod def bit_adder_selection(cls, a, b): + if cls.linear_rounds: + return cls.ripple_carry_adder(a, b) # experimental cut-off with dead code elimination - if len(a) < 122 or cls.log_rounds: + elif len(a) < 122 or cls.log_rounds: return cls.carry_lookahead_adder(a, b) else: return cls.carry_select_adder(a, b) @@ -1992,27 +2113,18 @@ def print_plain(self): print_float_plain(cint(abs_v), cint(-self.f), \ cint(0), cint(sign)) -class _fix(_number, _structure): - """ Shared fixed point type. """ - __slots__ = ['v', 'f', 'k', 'size'] +class _single(_number, _structure): + """ Representation as single integer preserving the order """ + """ E.g. fixed-point numbers """ + __slots__ = ['v'] kappa = 40 + round_nearest = False @property @classmethod def reg_type(cls): return cls.int_type.reg_type - @classmethod - def set_precision(cls, f, k = None): - cls.f = f - # default bitlength = 2*precision - if k is None: - cls.k = 2 * f - else: - if k < f: - raise CompilerError('bit length cannot be less than precision') - cls.k = k - @classmethod def receive_from_client(cls, n, client_id, message_type=ClientMessageType.NoType): """ Securely obtain shares of n values input by a client. @@ -2022,15 +2134,7 @@ def receive_from_client(cls, n, client_id, message_type=ClientMessageType.NoType @vectorized_classmethod def load_mem(cls, address, mem_type=None): - res = [] - res.append(cls.int_type.load_mem(address)) - return cls(*res) - - @classmethod - def from_sint(cls, other): - res = cls() - res.load_int(cls.int_type.conv(other)) - return res + return cls._new(cls.int_type.load_mem(address)) @classmethod def conv(cls, other): @@ -2055,6 +2159,129 @@ def malloc(cls, size): def n_elements(): return 1 + @classmethod + def dot_product(cls, x, y, res_params=None): + dp = cls.int_type.dot_product([xx.v for xx in x], [yy.v for yy in y]) + return x[0].unreduced(dp, y[0], res_params, len(x)).reduce_after_mul() + + @classmethod + def row_matrix_mul(cls, row, matrix, res_params=None): + int_matrix = [y.get_vector().pre_mul() for y in matrix] + col = cls.int_type.row_matrix_mul([x.pre_mul() for x in row], + int_matrix) + res = row[0].unreduced(col, matrix[0][0], res_params, + len(row)).reduce_after_mul() + return res + + @classmethod + def matrix_mul(cls, A, B, n, res_params=None): + AA = A.pre_mul() + BB = B.pre_mul() + CC = cls.int_type.matrix_mul(AA, BB, n) + res = A.unreduced(CC, B, res_params, n).reduce_after_mul() + return res + + def store_in_mem(self, address): + self.v.store_in_mem(address) + + @property + def size(self): + return self.v.size + + def sizeof(self): + return self.size + + def __len__(self): + return len(self.v) + + @vectorize + def __sub__(self, other): + other = self.coerce(other) + return self + (-other) + + def __rsub__(self, other): + return -self + other + + @vectorize + def __eq__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.equal(other.v, self.k, self.kappa) + else: + raise NotImplementedError + + @vectorize + def __le__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.less_equal(other.v, self.k, self.kappa) + else: + raise NotImplementedError + + @vectorize + def __lt__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.less_than(other.v, self.k, self.kappa) + else: + raise NotImplementedError + + @vectorize + def __ge__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.greater_equal(other.v, self.k, self.kappa) + else: + raise NotImplementedError + + @vectorize + def __gt__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.greater_than(other.v, self.k, self.kappa) + else: + raise NotImplementedError + + @vectorize + def __ne__(self, other): + other = self.coerce(other) + if isinstance(other, (cfix, _single)): + return self.v.not_equal(other.v, self.k, self.kappa) + else: + raise NotImplementedError + +class _fix(_single): + """ Shared fixed point type. """ + __slots__ = ['v', 'f', 'k', 'size'] + + @classmethod + def set_precision(cls, f, k = None): + cls.f = f + # default bitlength = 2*precision + if k is None: + cls.k = 2 * f + else: + if k < f: + raise CompilerError('bit length cannot be less than precision') + cls.k = k + + @classmethod + def coerce(cls, other): + if isinstance(other, _fix): + return other + else: + return cls.conv(other) + + @classmethod + def from_sint(cls, other): + res = cls() + res.load_int(cls.int_type.conv(other)) + return res + + @classmethod + def _new(cls, other): + return cls(other) + @vectorize_init def __init__(self, _v=None, size=None): self.size = get_global_vector_size() @@ -2066,6 +2293,7 @@ def __init__(self, _v=None, size=None): self.v = self.int_type(0) elif isinstance(_v, self.int_type): self.v = _v + self.size = _v.size elif isinstance(_v, cfix.scalars): self.v = self.int_type(int(round(_v * (2 ** f))), size=self.size) elif isinstance(_v, self.float_type): @@ -2077,7 +2305,7 @@ def __init__(self, _v=None, size=None): self.v = _v.v elif isinstance(_v, (MemValue, MemFix)): #this is a memvalue object - self.v = sfix(_v.read()).v + self.v = type(self)(_v.read()).v else: raise CompilerError('cannot convert %s to sfix' % _v) if not isinstance(self.v, self.int_type): @@ -2087,12 +2315,6 @@ def __init__(self, _v=None, size=None): def load_int(self, v): self.v = self.int_type(v) << self.f - def store_in_mem(self, address): - self.v.store_in_mem(address) - - def sizeof(self): - return self.size * 4 - @vectorize def add(self, other): other = self.coerce(other) @@ -2108,8 +2330,12 @@ def add(self, other): def mul(self, other): other = self.coerce(other) if isinstance(other, _fix): - val = self.v.TruncMul(other.v, self.k * 2, self.f, self.kappa) - return type(self)(val) + val = self.v.TruncMul(other.v, self.k * 2, self.f, self.kappa, + self.round_nearest) + if self.size >= other.size: + return self._new(val) + else: + return self.vec._new(val) elif isinstance(other, cfix): res = type(self)((self.v * other.v) >> self.f) return res @@ -2119,66 +2345,10 @@ def mul(self, other): else: raise CompilerError('Invalid type %s for _fix.__mul__' % type(other)) - @vectorize - def __sub__(self, other): - other = self.coerce(other) - return self + (-other) - @vectorize def __neg__(self): return type(self)(-self.v) - def __rsub__(self, other): - return -self + other - - @vectorize - def __eq__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.equal(other.v, self.k, self.kappa) - else: - raise NotImplementedError - - @vectorize - def __le__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.less_equal(other.v, self.k, self.kappa) - else: - raise NotImplementedError - - @vectorize - def __lt__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.less_than(other.v, self.k, self.kappa) - else: - raise NotImplementedError - - @vectorize - def __ge__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.greater_equal(other.v, self.k, self.kappa) - else: - raise NotImplementedError - - @vectorize - def __gt__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.greater_than(other.v, self.k, self.kappa) - else: - raise NotImplementedError - - @vectorize - def __ne__(self, other): - other = self.coerce(other) - if isinstance(other, (cfix, _fix)): - return self.v.not_equal(other.v, self.k, self.kappa) - else: - raise NotImplementedError - @vectorize def __div__(self, other): other = self.coerce(other) @@ -2211,6 +2381,38 @@ class sfix(_fix): def coerce(cls, other): return parse_type(other) + def mul_no_reduce(self, other, res_params=None): + return self.unreduced(self.v * other.v) + + def pre_mul(self): + return self.v + + def unreduced(self, v, other=None, res_params=None, n_summands=1): + return unreduced_sfix(v, self.k * 2, self.f, self.kappa) + +class unreduced_sfix(object): + def __init__(self, v, k, m, kappa): + self.v = v + self.k = k + self.m = m + self.kappa = kappa + self.size = self.v.size + + def __add__(self, other): + if other in (0, 0L): + return self + assert self.k == other.k + assert self.m == other.m + assert self.kappa == other.kappa + return unreduced_sfix(self.v + other.v, self.k, self.m, self.kappa) + + __radd__ = __add__ + + @vectorize + def reduce_after_mul(self): + return sfix(sfix.int_type.round(self.v, self.k, self.m, self.kappa, + nearest=sfix.round_nearest)) + # this is for 20 bit decimal precision # with 40 bitlength of entire number # these constants have been chosen for multiplications to fit in 128 bit prime field @@ -2223,6 +2425,192 @@ def coerce(cls, other): sfix.set_precision(fixed_lower, fixed_upper) cfix.set_precision(fixed_lower, fixed_upper) +class squant(_single): + """ Quantization as in ArXiv:1712.05877v1 """ + __slots__ = ['params'] + int_type = sint + # cheaper probabilistic truncation + max_length = 63 + clamp = True + + @classmethod + def set_params(cls, S, Z=0, k=8): + cls.params = squant_params(S, Z, k) + + @classmethod + def from_sint(cls, other): + raise CompilerError('sint to squant conversion not implemented') + + @classmethod + def _new(cls, value, params=None): + res = cls(params=params) + res.v = value + return res + + @read_mem_value + def __init__(self, value=None, params=None): + if params is not None: + self.params = params + if value is None: + # need to set v manually + pass + elif isinstance(value, cfix.scalars): + set_global_vector_size(1) + q = util.round_to_int(value / self.S + self.Z) + if util.is_constant(q) and (q < 0 or q >= 2**self.k): + raise CompilerError('%f not quantizable' % value) + self.v = self.int_type(q) + reset_global_vector_size() + elif isinstance(value, type(self)): + self.v = value.v + else: + raise CompilerError('cannot convert %s to squant' % value) + + def __getitem__(self, index): + return type(self)._new(self.v[index], self.params) + + def get_params(self): + return self.params + + @property + def S(self): + return self.params.S + @property + def Z(self): + return self.params.Z + @property + def k(self): + return self.params.k + + def coerce(self, other): + other = self.conv(other) + return self._new(util.expand(other.v, self.size), other.params) + + @vectorize + def add(self, other): + other = self.coerce(other) + assert self.get_params() == other.get_params() + return self._new(self.v + other.v - util.expand(self.Z, self.v.size)) + + def mul(self, other, res_params=None): + return self.mul_no_reduce(other, res_params).reduce_after_mul() + + def mul_no_reduce(self, other, res_params=None): + if isinstance(other, sint): + return self._new(other * (self.v - self.Z) + self.Z, + params=self.get_params()) + other = self.coerce(other) + tmp = (self.v - self.Z) * (other.v - other.Z) + return _unreduced_squant(tmp, (self.get_params(), other.get_params()), + res_params=res_params) + + def pre_mul(self): + return self.v - util.expand(self.Z, self.v.size) + + def unreduced(self, v, other, res_params=None, n_summands=1): + return _unreduced_squant(v, (self.get_params(), other.get_params()), + res_params, n_summands) + + @vectorize + def for_mux(self, other): + other = self.coerce(other) + assert self.params == other.params + f = lambda x: self._new(x, self.params) + return f, self.v, other.v + + @vectorize + def __neg__(self): + return self._new(-self.v + 2 * util.expand(self.Z, self.v.size)) + +class _unreduced_squant(object): + def __init__(self, v, params, res_params=None, n_summands=1): + self.v = v + self.params = params + self.n_summands = n_summands + self.res_params = res_params or params[0] + + def __add__(self, other): + if other in (0, 0L): + return self + assert self.params == other.params + assert self.res_params == other.res_params + return _unreduced_squant(self.v + other.v, self.params, self.res_params, + self.n_summands + other.n_summands) + + __radd__ = __add__ + + def reduce_after_mul(self): + return squant_params.conv(self.res_params).reduce(self) + +class squant_params(object): + max_n_summands = 2048 + + @staticmethod + def conv(other): + if isinstance(other, squant_params): + return other + else: + return squant_params(*other) + + def __init__(self, S, Z=0, k=8): + try: + self.S = float(S) + except: + self.S = S + self.Z = Z + self.k = k + self._store = {} + + def __iter__(self): + yield self.S + yield self.Z + yield self.k + + def is_constant(self): + return util.is_constant_float(self.S) and util.is_constant(self.Z) + + def get(self, input_params, n_summands): + p = input_params + M = p[0].S * p[1].S / self.S + logM = util.log2(M) + n_shift = squant.max_length - p[0].k - p[1].k - util.log2(n_summands) + if util.is_constant_float(M): + n_shift -= logM + int_mult = int(round(M * 2 ** (n_shift))) + else: + int_mult = MemValue(M.v << (n_shift + M.p)) + shifted_Z = MemValue.if_necessary(self.Z << n_shift) + return n_shift, int_mult, shifted_Z + + def precompute(self, *input_params): + self._store[input_params] = self.get(input_params, self.max_n_summands) + + def get_stored(self, unreduced): + assert unreduced.n_summands <= self.max_n_summands + return self._store[unreduced.params] + + def reduce(self, unreduced): + ps = (self,) + unreduced.params + if reduce(operator.and_, (p.is_constant() for p in ps)): + n_shift, int_mult, shifted_Z = self.get(unreduced.params, + unreduced.n_summands) + else: + n_shift, int_mult, shifted_Z = self.get_stored(unreduced) + size = unreduced.v.size + n_shift = util.expand(n_shift, size) + shifted_Z = util.expand(shifted_Z, size) + tmp = unreduced.v * int_mult + shifted_Z + shifted = tmp.round(squant.max_length, n_shift, + squant.kappa, squant.round_nearest) + if squant.clamp: + length = max(self.k, squant.max_length - n_shift) + 1 + top = (1 << self.k) - 1 + over = shifted.greater_than(top, length, squant.kappa) + under = shifted.less_than(0, length, squant.kappa) + shifted = over.if_else(top, shifted) + shifted = under.if_else(0, shifted) + return squant._new(shifted, params=self) + class sfloat(_number, _structure): """ Shared floating point data type, representing (1 - 2s)*(1 - z)*v*2^p. @@ -2238,7 +2626,6 @@ class sfloat(_number, _structure): plen = 8 kappa = 40 round_nearest = False - error = 0 @staticmethod def n_elements(): @@ -2257,16 +2644,20 @@ def is_address_tuple(cls, address): @vectorized_classmethod def load_mem(cls, address, mem_type=None): + size = get_global_vector_size() if cls.is_address_tuple(address): - return sfloat(*(sint.load_mem(a) for a in address)) + return sfloat(*(sint.load_mem(a, size=size) for a in address)) res = [] for i in range(4): - res.append(sint.load_mem(address + i * get_global_vector_size())) + res.append(sint.load_mem(address + i * size, size=size)) return sfloat(*res) @classmethod def set_error(cls, error): - cls.error += error - cls.error * error + # incompatible with loops + #cls.error += error - cls.error * error + cls.error = error + pass @classmethod def conv(cls, other): @@ -2349,6 +2740,9 @@ def __init__(self, v, p=None, z=None, s=None, size=None): else: self.s = s + def __getitem__(self, index): + return sfloat(*(x[index] for x in self)) + def __iter__(self): yield self.v yield self.p @@ -2361,13 +2755,14 @@ def store_in_mem(self, address): x.store_in_mem(a) return for i,x in enumerate((self.v, self.p, self.z, self.s)): - x.store_in_mem(address + i * get_global_vector_size()) + x.store_in_mem(address + i * self.size) def sizeof(self): return self.size * self.n_elements() @vectorize def add(self, other): + other = self.conv(other) if isinstance(other, sfloat): a,c,d,e = [sint() for i in range(4)] t = sint() @@ -2451,8 +2846,9 @@ def add(self, other): else: return NotImplemented - @vectorize + @vectorize_max def mul(self, other): + other = self.conv(other) if isinstance(other, sfloat): v1 = sint() v2 = sint() @@ -2467,9 +2863,12 @@ def mul(self, other): t = v1 - c2expl comparison.LTZ(b, t, self.vlen+1, self.kappa) comparison.Trunc(v2, b*v1 + v1, self.vlen+1, 1, self.kappa, False) - z = self.z + other.z - self.z*other.z # = OR(z1, z2) - s = self.s + other.s - 2*self.s*other.s # = XOR(s1,s2) - p = (self.p + other.p - b + self.vlen)*(1 - z) + z1, z2, s1, s2, p1, p2 = (x.expand_to_vector() for x in \ + (self.z, other.z, self.s, other.s, + self.p, other.p)) + z = z1 + z2 - self.z*other.z # = OR(z1, z2) + s = s1 + s2 - self.s*other.s*2 # = XOR(s1,s2) + p = (p1 + p2 - b + self.vlen)*(1 - z) return sfloat(v2, p, z, s) else: return NotImplemented @@ -2481,8 +2880,9 @@ def __rsub__(self, other): raise NotImplementedError() def __div__(self, other): + other = self.conv(other) v = floatingpoint.SDiv(self.v, other.v + other.z * (2**self.vlen - 1), - self.vlen, self.kappa) + self.vlen, self.kappa, self.round_nearest) b = v.less_than(two_power(self.vlen-1), self.vlen + 1, self.kappa) overflow = v.greater_equal(two_power(self.vlen), self.vlen + 1, self.kappa) underflow = v.less_than(two_power(self.vlen-2), self.vlen + 1, self.kappa) @@ -2495,9 +2895,18 @@ def __div__(self, other): sfloat.set_error(other.z) return sfloat(v, p, z, s) + def __rdiv__(self, other): + return self.conv(other) / self + @vectorize def __neg__(self): return sfloat(self.v, self.p, self.z, (1 - self.s) * (1 - self.z)) + + def __abs__(self): + if self.s: + return -self + else: + return self @vectorize def __lt__(self, other): @@ -2535,6 +2944,18 @@ def __eq__(self, other): def __ne__(self, other): return 1 - (self == other) + def log2(self): + up = self.v.greater_than(1 << (self.vlen - 1), self.vlen, self.kappa) + return self.p + self.vlen - 1 + up + + def round_to_int(self): + direction = self.p.greater_equal(-self.vlen, self.plen, self.kappa) + right = self.v.right_shift(-self.p - 1, self.vlen + 1, self.kappa) + up = right.mod2m(1, self.vlen + 1, self.kappa) + right = right.right_shift(1, self.vlen + 1, self.kappa) + up + abs_value = direction * right + return self.s.if_else(-abs_value, abs_value) + def value(self): """ Gets actual floating point value, if emulation is enabled. """ return (1 - 2*self.s.value)*(1 - self.z.value)*self.v.value/float(2**self.p.value) @@ -2603,8 +3024,13 @@ def get_address(self, index): (str(index), str(self.length))) if (program.curr_block, index) not in self.address_cache: n = self.value_type.n_elements() + length = self.length + if n == 1: + # length can be None for single-element arrays + length = 0 self.address_cache[program.curr_block, index] = \ - util.untuplify([self.address + index * n + i for i in range(n)]) + util.untuplify([self.address + index + i * length \ + for i in range(n)]) if self.debug: library.print_ln_if(index >= self.length, 'OF:' + self.debug) library.print_ln_if(self.address_cache[program.curr_block, index] >= program.allocated_mem[self.value_type.reg_type], 'AOF:' + self.debug) @@ -2619,7 +3045,7 @@ def __getitem__(self, index): if isinstance(index, slice): start, stop, step = self.get_slice(index) res_length = (stop - start - 1) / step + 1 - res = self.value_type.Array(res_length) + res = Array(res_length, self.value_type) @library.for_range(res_length) def f(i): res[i] = self[start+i*step] @@ -2683,6 +3109,9 @@ def f(i): self[i] = mem_value return self + def get_vector(self): + return self.value_type.load_mem(self.address, size=self.length) + def get_mem_value(self, index): return MemValue(self[index], self.get_address(index)) @@ -2708,8 +3137,7 @@ class SubMultiArray(object): def __init__(self, sizes, value_type, address, index, debug=None): self.sizes = sizes self.value_type = _get_type(value_type) - self.address = address + index * reduce(operator.mul, self.sizes) * \ - self.value_type.n_elements() + self.address = address + index * self.total_size() self.sub_cache = {} self.debug = debug if debug: @@ -2744,37 +3172,81 @@ def f(i): self[i].assign_all(value) return self + def total_size(self): + return reduce(operator.mul, self.sizes) * self.value_type.n_elements() + + def get_vector(self): + return self.value_type.load_mem(self.address, size=self.total_size()) + + def assign_vector(self, vector): + assert vector.size == self.total_size() + vector.store_in_mem(self.address) + class MultiArray(SubMultiArray): - def __init__(self, sizes, value_type, debug=None): + def __init__(self, sizes, value_type, debug=None, address=None): self.array = Array(reduce(operator.mul, sizes), \ - value_type) + value_type, address=address) SubMultiArray.__init__(self, sizes, value_type, self.array.address, 0, \ debug=debug) if len(sizes) < 2: raise CompilerError('Use Array') class Matrix(MultiArray): - def __init__(self, rows, columns, value_type, debug=None): - MultiArray.__init__(self, [rows, columns], value_type, debug=debug) + def __init__(self, rows, columns, value_type, debug=None, address=None): + MultiArray.__init__(self, [rows, columns], value_type, debug=debug, \ + address=address) + + def __setitem__(self, index, other): + assert other.size == self.sizes[1] + other.store_in_mem(self[index].address) def __mul__(self, other): + return self.mul(other) + + def mul(self, other, res_params=None): if isinstance(other, Array): assert len(other) == self.sizes[1] - res = [None] * self.sizes[0] - for i in range(self.sizes[0]): - res[i] = sum(x * y for x, y in zip(self[i], other)) - res_array = Array(self.sizes[0], type(res[0])) - res_array.assign(res) - return res_array + if self.value_type.n_elements() == 1: + matrix = Matrix(len(other), 1, other.value_type, \ + address=other.address) + res = self * matrix + return Array(res.sizes[0], res.value_type, address=res.address) + else: + matrix = Matrix(len(other), 1, other.value_type) + for i, x in enumerate(other): + matrix[i][0] = x + res = self * matrix + return Array.create_from(x[0] for x in res) elif isinstance(other, Matrix): assert other.sizes[0] == self.sizes[1] - res = [None] * self.sizes[0] * other.sizes[1] - for i in range(self.sizes[0]): - for j in range(other.sizes[1]): - res[i * other.sizes[1] + j] = sum(self[i][k] * other[k][j] \ - for k in range(self.sizes[1])) - res_matrix = Matrix(self.sizes[0], other.sizes[1], type(res[0])) - res_matrix.array.assign(res) + if res_params is not None: + class t(self.value_type): + pass + t.params = res_params + else: + t = self.value_type + res_matrix = Matrix(self.sizes[0], other.sizes[1], t) + try: + A = self.get_vector() + B = other.get_vector() + res_matrix.assign_vector( + self.value_type.matrix_mul(A, B, self.sizes[1], + res_params)) + except AttributeError: + # fallback for sfloat etc. + @library.for_range(self.sizes[0]) + def _(i): + try: + res_matrix[i] = self.value_type.row_matrix_mul( + self[i], other, res_params) + except AttributeError: + # fallback for binary circuits + @library.for_range(other.sizes[1]) + def _(j): + res_matrix[i][j] = 0 + @library.for_range(self.sizes[0]) + def _(k): + res_matrix[i][j] += self[i][k] * other[k][j] return res_matrix else: raise NotImplementedError @@ -2853,6 +3325,13 @@ class _mem(_number): class MemValue(_mem): __slots__ = ['last_write_block', 'reg_type', 'register', 'address', 'deleted'] + @classmethod + def if_necessary(cls, value): + if util.is_constant_float(value): + return value + else: + return cls(value) + def __init__(self, value, address=None): self.last_write_block = None if isinstance(value, int): @@ -2923,6 +3402,9 @@ def reveal(self): if_else = lambda self,*args,**kwargs: self.read().if_else(*args, **kwargs) + expand_to_vector = lambda self,*args,**kwargs: \ + self.read().expand_to_vector(*args, **kwargs) + def __repr__(self): return 'MemValue(%s,%d)' % (self.value_type, self.address) diff --git a/Compiler/util.py b/Compiler/util.py index b2bcd35..403a81f 100644 --- a/Compiler/util.py +++ b/Compiler/util.py @@ -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 diff --git a/FHEOffline/SimpleEncCommit.cpp b/FHEOffline/SimpleEncCommit.cpp index 25b86f4..c4c2cd1 100644 --- a/FHEOffline/SimpleEncCommit.cpp +++ b/FHEOffline/SimpleEncCommit.cpp @@ -340,12 +340,14 @@ void MultiEncCommit::add_ciphertexts(vector& ciphertexts, template class SimpleEncCommitBase; template class SimpleEncCommit; +template class SimpleEncCommitFactory; template class SummingEncCommit; template class NonInteractiveProofSimpleEncCommit; template class MultiEncCommit; template class SimpleEncCommitBase; template class SimpleEncCommit; +template class SimpleEncCommitFactory; template class SummingEncCommit; template class NonInteractiveProofSimpleEncCommit; template class MultiEncCommit; diff --git a/Fake-Offline.cpp b/Fake-Offline.cpp index 7c80a44..1721d45 100644 --- a/Fake-Offline.cpp +++ b/Fake-Offline.cpp @@ -14,6 +14,7 @@ #include "Tools/benchmarking.h" #include "Auth/fake-stuff.hpp" +#include "Processor/Data_Files.hpp" #include #include diff --git a/GC/Machine.cpp b/GC/Machine.cpp index 43ec27a..384670d 100644 --- a/GC/Machine.cpp +++ b/GC/Machine.cpp @@ -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 { diff --git a/GC/MaliciousRepThread.cpp b/GC/MaliciousRepThread.cpp index 966d332..dd72830 100644 --- a/GC/MaliciousRepThread.cpp +++ b/GC/MaliciousRepThread.cpp @@ -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& 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; diff --git a/GC/square64.cpp b/GC/square64.cpp index 5a5683b..a10351d 100644 --- a/GC/square64.cpp +++ b/GC/square64.cpp @@ -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) diff --git a/Machines/Rep.cpp b/Machines/Rep.cpp new file mode 100644 index 0000000..7342fd6 --- /dev/null +++ b/Machines/Rep.cpp @@ -0,0 +1,49 @@ +/* + * Rep.cpp + * + */ + +#include "Processor/Data_Files.hpp" +#include "Processor/Instruction.hpp" +#include "Processor/Machine.hpp" + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + return new ReplicatedPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + return new ReplicatedPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + return new ReplicatedRingPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + (void) proc; + return new MaliciousRepPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + (void) proc; + return new MaliciousRepPrep>(proc); +} + +template class Machine, Rep3Share>; +template class Machine, Rep3Share>; +template class Machine, MaliciousRep3Share>; diff --git a/Machines/SPDZ.cpp b/Machines/SPDZ.cpp new file mode 100644 index 0000000..4550a84 --- /dev/null +++ b/Machines/SPDZ.cpp @@ -0,0 +1,6 @@ + +#include "Processor/Data_Files.hpp" +#include "Processor/Instruction.hpp" +#include "Processor/Machine.hpp" + +template class Machine>; diff --git a/Processor/ShamirMachine.cpp b/Machines/ShamirMachine.cpp similarity index 60% rename from Processor/ShamirMachine.cpp rename to Machines/ShamirMachine.cpp index 75b12f2..5e84207 100644 --- a/Processor/ShamirMachine.cpp +++ b/Machines/ShamirMachine.cpp @@ -3,13 +3,17 @@ * */ -#include "ShamirMachine.h" +#include #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::ShamirMachineSpec(int argc, const char** argv) : ReplicatedMachine, T>(argc, argv, "shamir", opt, nparties); } +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + return new ReplicatedPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + return new ReplicatedPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + (void) proc; + return new MaliciousRepPrep>(proc); +} + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc) +{ + (void) proc; + return new MaliciousRepPrep>(proc); +} + template class ShamirMachineSpec; template class ShamirMachineSpec; + +template class Machine, ShamirShare>; +template class Machine, MaliciousShamirShare>; diff --git a/Processor/ShamirMachine.h b/Machines/ShamirMachine.h similarity index 79% rename from Processor/ShamirMachine.h rename to Machines/ShamirMachine.h index 4999078..108cfd0 100644 --- a/Processor/ShamirMachine.h +++ b/Machines/ShamirMachine.h @@ -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 @@ class ShamirMachineSpec : ShamirMachine ShamirMachineSpec(int argc, const char** argv); }; -#endif /* PROCESSOR_SHAMIRMACHINE_H_ */ +#endif /* MACHINES_SHAMIRMACHINE_H_ */ diff --git a/Makefile b/Makefile index 44e555f..bf69fc2 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/Math/BitVec.h b/Math/BitVec.h index fe3786a..5ab2f66 100644 --- a/Math/BitVec.h +++ b/Math/BitVec.h @@ -17,6 +17,8 @@ class BitVec : public IntBase 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) {} diff --git a/Math/Integer.h b/Math/Integer.h index 7b50d13..ee3ebcf 100644 --- a/Math/Integer.h +++ b/Math/Integer.h @@ -27,6 +27,8 @@ class IntBase 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); diff --git a/Math/Rep3Share.h b/Math/Rep3Share.h index 298b84e..dd4216e 100644 --- a/Math/Rep3Share.h +++ b/Math/Rep3Share.h @@ -83,6 +83,11 @@ class Rep3Share : public FixedVec *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; diff --git a/Math/Zp_Data.h b/Math/Zp_Data.h index deb534b..01c693d 100644 --- a/Math/Zp_Data.h +++ b/Math/Zp_Data.h @@ -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 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; diff --git a/Math/field_types.h b/Math/field_types.h index fe5c0bb..a361e48 100644 --- a/Math/field_types.h +++ b/Math/field_types.h @@ -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_ */ diff --git a/Math/gf2n.cpp b/Math/gf2n.cpp index 1a3240c..d0d4b47 100644 --- a/Math/gf2n.cpp +++ b/Math/gf2n.cpp @@ -91,7 +91,11 @@ void gf2n_short::init_field(int nn) mask=(1ULL< 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_(res, x, y); } +#endif #endif /* MATH_MPN_FIXED_H_ */ diff --git a/Math/operators.h b/Math/operators.h index 421677c..d6594eb 100644 --- a/Math/operators.h +++ b/Math/operators.h @@ -8,8 +8,8 @@ template T operator*(const bool& x, const T& y) { return x ? y : T(); } -template -T operator*(const T& y, const bool& x) { return x ? y : T(); } +//template +//T operator*(const T& y, const bool& x) { return x ? y : T(); } template T& operator*=(const T& y, const bool& x) { y = x ? y : T(); return y; } diff --git a/Networking/CryptoPlayer.cpp b/Networking/CryptoPlayer.cpp index d7051ff..02c70d2 100644 --- a/Networking/CryptoPlayer.cpp +++ b/Networking/CryptoPlayer.cpp @@ -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]; diff --git a/Networking/Player.cpp b/Networking/Player.cpp index d398d82..33771df 100644 --- a/Networking/Player.cpp +++ b/Networking/Player.cpp @@ -188,10 +188,15 @@ template<> MultiPlayer::~MultiPlayer() { /* Close down the sockets */ - for (int i=0; i +MultiPlayer::~MultiPlayer() +{ +} Player::~Player() { @@ -336,6 +341,11 @@ void MultiPlayer::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 void MultiPlayer::pass_around(octetStream& o, int offset) const diff --git a/Networking/Player.h b/Networking/Player.h index 7098bc1..342b42a 100644 --- a/Networking/Player.h +++ b/Networking/Player.h @@ -169,6 +169,10 @@ class Player : public PlayerBase void receive_relative(vector& 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 @@ class MultiPlayer : public Player // 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]; } diff --git a/Networking/sockets.cpp b/Networking/sockets.cpp index 2aed68b..ed70429 100644 --- a/Networking/sockets.cpp +++ b/Networking/sockets.cpp @@ -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); diff --git a/Networking/sockets.h b/Networking/sockets.h index 3e3069d..07e4a8c 100644 --- a/Networking/sockets.h +++ b/Networking/sockets.h @@ -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; diff --git a/Networking/ssl_sockets.h b/Networking/ssl_sockets.h index 197f41c..a078126 100644 --- a/Networking/ssl_sockets.h +++ b/Networking/ssl_sockets.h @@ -14,12 +14,17 @@ typedef boost::asio::ssl::stream 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<> diff --git a/OT/BitMatrix.cpp b/OT/BitMatrix.cpp index 9fb9971..01ccda1 100644 --- a/OT/BitMatrix.cpp +++ b/OT/BitMatrix.cpp @@ -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; diff --git a/OT/BitVector.h b/OT/BitVector.h index 98282de..10c94da 100644 --- a/OT/BitVector.h +++ b/OT/BitVector.h @@ -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 diff --git a/Player-Online.cpp b/Player-Online.cpp index 407bfd8..a8d59fa 100644 --- a/Player-Online.cpp +++ b/Player-Online.cpp @@ -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>(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) diff --git a/Processor/BaseMachine.cpp b/Processor/BaseMachine.cpp new file mode 100644 index 0000000..0c16d06 --- /dev/null +++ b/Processor/BaseMachine.cpp @@ -0,0 +1,94 @@ +/* + * BaseMachine.cpp + * + */ + +#include "BaseMachine.h" + +#include +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> 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::iterator it = timer.begin(); it != timer.end(); it++) + cerr << "Time" << it->first << " = " << it->second.elapsed() << " seconds " << endl; +} diff --git a/Processor/Beaver.h b/Processor/Beaver.h index 99abbec..a284456 100644 --- a/Processor/Beaver.h +++ b/Processor/Beaver.h @@ -7,22 +7,34 @@ #define PROCESSOR_BEAVER_H_ #include +#include using namespace std; +#include "Replicated.h" + template class SubProcessor; template class MAC_Check_Base; class Player; template -class Beaver +class Beaver : public ProtocolBase { + vector shares; + vector opened; + vector> triples; + typename vector::iterator it; + typename vector>::iterator triple; + SubProcessor* proc; + public: Player& P; - static void muls(const vector& reg, SubProcessor& proc, - MAC_Check_Base& MC, int size); + Beaver(Player& P) : proc(0), P(P) {} - Beaver(Player& P) : P(P) {} + void init_mul(SubProcessor* proc); + typename T::clear prepare_mul(const T& x, const T& y); + void exchange(); + T finalize_mul(); }; #endif /* PROCESSOR_BEAVER_H_ */ diff --git a/Processor/Beaver.hpp b/Processor/Beaver.hpp index 75934bb..d19ed23 100644 --- a/Processor/Beaver.hpp +++ b/Processor/Beaver.hpp @@ -7,44 +7,46 @@ #include + template -void Beaver::muls(const vector& reg, SubProcessor& proc, MAC_Check_Base& MC, - int size) +void Beaver::init_mul(SubProcessor* proc) { - assert(reg.size() % 3 == 0); - int n = reg.size() / 3; - vector& shares = proc.Sh_PO; - vector& opened = proc.PO; + this->proc = proc; shares.clear(); - vector> triples(n * size); - auto triple = triples.begin(); + opened.clear(); + triples.clear(); +} - 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++; - } +template +typename T::clear Beaver::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; +} - MC.POpen_Begin(opened, shares, proc.P); - MC.POpen_End(opened, shares, proc.P); - auto it = opened.begin(); +template +void Beaver::exchange() +{ + proc->MC.POpen(opened, shares, P); + 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++; - } +template +T Beaver::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; } diff --git a/Processor/Data_Files.h b/Processor/Data_Files.h index 7186017..019d82a 100644 --- a/Processor/Data_Files.h +++ b/Processor/Data_Files.h @@ -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 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 { template friend class Sub_Data_Files; - static const bool implemented[N_DTYPE]; - static map tuple_lengths; static Lock tuple_lengths_lock; diff --git a/Processor/Data_Files.cpp b/Processor/Data_Files.hpp similarity index 64% rename from Processor/Data_Files.cpp rename to Processor/Data_Files.hpp index dff1c2a..9e4f132 100644 --- a/Processor/Data_Files.cpp +++ b/Processor/Data_Files.hpp @@ -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 #include -const char* DataPositions::field_names[] = { "gfp", "gf2n", "bit", "int64" }; - -template<> -const bool Sub_Data_Files::implemented[N_DTYPE] = - { true, true, true, true, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { true, true, true, true, true, true } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { false, false, true, false, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { true, true, true, true, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { true, true, true, true, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { true, true, true, true, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { true, true, true, true, false, false } -; - -template<> -const bool Sub_Data_Files::implemented[N_DTYPE] = - { true, false, true, false, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { false, false, false, false, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { false, false, false, false, false, false } -; - -template<> -const bool Sub_Data_Files>::implemented[N_DTYPE] = - { false, false, false, false, false, false } -; - -template<> -const bool Sub_Data_Files>::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::tuple_lengths_lock; template map Sub_Data_Files::tuple_lengths; -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - return new ReplicatedPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - return new ReplicatedPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - return new ReplicatedRingPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - (void) proc; - return new MaliciousRepPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - (void) proc; - return new MaliciousRepPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - return new ReplicatedPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - return new ReplicatedPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - (void) proc; - return new MaliciousRepPrep>(proc); -} - -template<> -Preprocessing>* Preprocessing>::get_live_prep( - SubProcessor>* proc) -{ - (void) proc; - return new MaliciousRepPrep>(proc); -} - template Preprocessing* Preprocessing::get_live_prep(SubProcessor* proc) { @@ -270,7 +143,7 @@ Sub_Data_Files::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::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::get(vector& S, DataTag tag, const vector& regs, for (unsigned int i = 0; i < regs.size(); i++) extended[tag].input(S[regs[i] + j]); } - -template class Sub_Data_Files>; -template class Sub_Data_Files; -template class Sub_Data_Files>; -template class Sub_Data_Files>; -template class Sub_Data_Files>; -template class Sub_Data_Files; -template class Sub_Data_Files>; -template class Sub_Data_Files>; - -template class Data_Files>; -template class Data_Files, Rep3Share>; -template class Data_Files, Rep3Share>; -template class Data_Files, MaliciousRep3Share>; -template class Data_Files, ShamirShare>; -template class Data_Files, MaliciousShamirShare>; diff --git a/Processor/Input.h b/Processor/Input.h index 5f50548..cd3e052 100644 --- a/Processor/Input.h +++ b/Processor/Input.h @@ -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; diff --git a/Processor/Instruction.h b/Processor/Instruction.h index 0114478..35d2fc0 100644 --- a/Processor/Instruction.h +++ b/Processor/Instruction.h @@ -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, diff --git a/Processor/Instruction.cpp b/Processor/Instruction.hpp similarity index 97% rename from Processor/Instruction.cpp rename to Processor/Instruction.hpp index a73773f..7d98b3a 100644 --- a/Processor/Instruction.cpp +++ b/Processor/Instruction.hpp @@ -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 #include @@ -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& 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& Proc) const while (Proc.PC>& Proc) const; -template void Program::execute(Processor, Rep3Share>& Proc) const; -template void Program::execute(Processor, Rep3Share>& Proc) const; -template void Program::execute(Processor, MaliciousRep3Share>& Proc) const; -template void Program::execute(Processor, ShamirShare>& Proc) const; -template void Program::execute(Processor, MaliciousShamirShare>& Proc) const; diff --git a/Processor/Machine.h b/Processor/Machine.h index 96015dd..6d84945 100644 --- a/Processor/Machine.h +++ b/Processor/Machine.h @@ -18,6 +18,7 @@ #include #include +#include using namespace std; template @@ -71,6 +72,8 @@ class Machine : public BaseMachine OnlineOptions opts; + atomic 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, diff --git a/Processor/Machine.cpp b/Processor/Machine.hpp similarity index 79% rename from Processor/Machine.cpp rename to Processor/Machine.hpp index cf64261..b2c78c6 100644 --- a/Processor/Machine.cpp +++ b/Processor/Machine.hpp @@ -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 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 Machine::Machine(int my_number, Names& playerNames, string progname_str, string memtype, int lg2, bool direct, @@ -50,7 +33,8 @@ Machine::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::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> 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 void Machine::load_program(string threadname, string filename) { @@ -345,6 +293,7 @@ void Machine::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::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::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::iterator it = timer.begin(); it != timer.end(); it++) - cerr << "Time" << it->first << " = " << it->second.elapsed() << " seconds " << endl; -} - template void Machine::reqbl(int n) { sint::clear::reqbl(n); } - -template class Machine>; -template class Machine, Rep3Share>; -template class Machine, Rep3Share>; -template class Machine, MaliciousRep3Share>; -template class Machine, ShamirShare>; -template class Machine, MaliciousShamirShare>; diff --git a/Processor/MaliciousRepPrep.hpp b/Processor/MaliciousRepPrep.hpp index de11306..e36d203 100644 --- a/Processor/MaliciousRepPrep.hpp +++ b/Processor/MaliciousRepPrep.hpp @@ -5,7 +5,7 @@ #include "MaliciousRepPrep.h" #include "Auth/Subroutines.h" -#include "Auth/MaliciousRepMC.hpp" +//#include "Auth/MaliciousRepMC.hpp" template MaliciousRepPrep::MaliciousRepPrep(SubProcessor* proc) : @@ -41,7 +41,7 @@ template void MaliciousRepPrep::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::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(P); for (int i = 0; i < buffer_size; i++) @@ -86,7 +86,7 @@ template void MaliciousRepPrep::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::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(P); for (int i = 0; i < buffer_size; i++) @@ -132,7 +132,7 @@ template void MaliciousRepPrep::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::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(P); for (int i = 0; i < buffer_size; i++) diff --git a/Processor/Online-Thread.hpp b/Processor/Online-Thread.hpp index 91b8539..0caf313 100644 --- a/Processor/Online-Thread.hpp +++ b/Processor/Online-Thread.hpp @@ -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; diff --git a/Processor/Processor.h b/Processor/Processor.h index 2bb739c..e6ed8c9 100644 --- a/Processor/Processor.h +++ b/Processor/Processor.h @@ -41,7 +41,7 @@ class SubProcessor template friend class Processor; template friend class SPDZ; - template friend class PrepLessProtocol; + template friend class ProtocolBase; template friend class Beaver; public: @@ -61,7 +61,9 @@ class SubProcessor void POpen_Stop(const vector& reg,const Player& P,int size); void POpen(const vector& reg,const Player& P,int size); - void muls(const vector& reg,const Player& P,int size); + void muls(const vector& reg, int size); + void mulrs(const vector& reg); + void dotprods(const vector& reg); vector& get_S() { diff --git a/Processor/Processor.hpp b/Processor/Processor.hpp index 6698c21..3f8a1ea 100644 --- a/Processor/Processor.hpp +++ b/Processor/Processor.hpp @@ -50,7 +50,7 @@ Processor::Processor(int thread_num,Player& P, template Processor::~Processor() { - cerr << "Sent " << sent << " elements in " << rounds << " rounds" << endl; + cerr << "Opened " << sent << " elements in " << rounds << " rounds" << endl; } template @@ -485,6 +485,85 @@ void SubProcessor::POpen(const vector& reg, const Player& P, POpen_Stop(dest, P, size); } +template +void SubProcessor::muls(const vector& reg, int size) +{ + assert(reg.size() % 3 == 0); + int n = reg.size() / 3; + + SubProcessor& 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 +void SubProcessor::mulrs(const vector& reg) +{ + assert(reg.size() % 4 == 0); + int n = reg.size() / 4; + + SubProcessor& 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 +void SubProcessor::dotprods(const vector& 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 ostream& operator<<(ostream& s,const Processor& P) { diff --git a/Processor/Program.cpp b/Processor/Program.cpp index c40fb4c..52f0474 100644 --- a/Processor/Program.cpp +++ b/Processor/Program.cpp @@ -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++) diff --git a/Processor/Replicated.h b/Processor/Replicated.h index 5ab70c1..617eb28 100644 --- a/Processor/Replicated.h +++ b/Processor/Replicated.h @@ -30,33 +30,42 @@ class ReplicatedBase Player& P; ReplicatedBase(Player& P); + + int get_n_relevant_players() { return P.num_players() - 1; } }; template -class PrepLessProtocol +class ProtocolBase { +public: int counter; -public: - PrepLessProtocol(); - virtual ~PrepLessProtocol(); + ProtocolBase(); + virtual ~ProtocolBase(); void muls(const vector& reg, SubProcessor& proc, MAC_Check_Base& MC, int size); + void mulrs(const vector& reg, SubProcessor& proc); + void dotprods(const vector& reg, SubProcessor& proc); virtual void init_mul(SubProcessor* 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* 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 Replicated : public ReplicatedBase, public PrepLessProtocol +class Replicated : public ReplicatedBase, public ProtocolBase { vector os; deque add_shares; + typename T::clear dotprod_share; + public: typedef ReplicatedMC MAC_Check; typedef ReplicatedInput Input; @@ -78,6 +87,13 @@ class Replicated : public ReplicatedBase, public PrepLessProtocol void exchange(); T finalize_mul(); + void prepare_reshare(const typename T::clear& share); + + void init_dotprod(SubProcessor* proc); + void prepare_dotprod(const T& x, const T& y); + void next_dotprod(); + T finalize_dotprod(int length); + T get_random(); }; diff --git a/Processor/Replicated.hpp b/Processor/Replicated.hpp index 10722f2..e830151 100644 --- a/Processor/Replicated.hpp +++ b/Processor/Replicated.hpp @@ -13,7 +13,7 @@ #include "GC/ReplicatedSecret.h" template -PrepLessProtocol::PrepLessProtocol() : counter(0) +ProtocolBase::ProtocolBase() : counter(0) { } @@ -38,36 +38,42 @@ inline ReplicatedBase::ReplicatedBase(Player& P) : P(P) } template -PrepLessProtocol::~PrepLessProtocol() +ProtocolBase::~ProtocolBase() { if (counter) cerr << "Number of multiplications: " << counter << endl; } template -void PrepLessProtocol::muls(const vector& reg, +void ProtocolBase::muls(const vector& reg, SubProcessor& proc, MAC_Check_Base& 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 +void ProtocolBase::mulrs(const vector& reg, + SubProcessor& proc) +{ + proc.mulrs(reg); +} - counter += n * size; +template +void ProtocolBase::dotprods(const vector& reg, + SubProcessor& proc) +{ + proc.dotprods(reg); +} + +template +T ProtocolBase::finalize_dotprod(int length) +{ + counter += length; + T res; + for (int i = 0; i < length; i++) + res += finalize_mul(); + return res; } template @@ -87,28 +93,34 @@ void Replicated::init_mul() } template -typename T::clear Replicated::prepare_mul(const T& x, +inline typename T::clear Replicated::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 +inline void Replicated::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 void Replicated::exchange() { - P.send_relative(1, os[0]); - P.receive_relative(- 1, os[0]); + P.pass_around(os[0], 1); } template -T Replicated::finalize_mul() +inline T Replicated::finalize_mul() { T result; result[0] = add_shares.front(); @@ -117,6 +129,34 @@ T Replicated::finalize_mul() return result; } +template +inline void Replicated::init_dotprod(SubProcessor* proc) +{ + init_mul(proc); + dotprod_share.assign_zero(); +} + +template +inline void Replicated::prepare_dotprod(const T& x, const T& y) +{ + dotprod_share += x.local_mul(y); +} + +template +inline void Replicated::next_dotprod() +{ + prepare_reshare(dotprod_share); + dotprod_share.assign_zero(); +} + +template +inline T Replicated::finalize_dotprod(int length) +{ + (void) length; + this->counter++; + return finalize_mul(); +} + template T Replicated::get_random() { diff --git a/Processor/ReplicatedInput.hpp b/Processor/ReplicatedInput.hpp index e7033fc..615e5ee 100644 --- a/Processor/ReplicatedInput.hpp +++ b/Processor/ReplicatedInput.hpp @@ -21,7 +21,7 @@ void ReplicatedInput::reset(int player) } template -void ReplicatedInput::add_mine(const typename T::clear& input) +inline void ReplicatedInput::add_mine(const typename T::clear& input) { auto& shares = this->shares; shares.push_back({}); @@ -89,7 +89,7 @@ void PrepLessInput::stop(int player, vector targets) } template -void ReplicatedInput::finalize_other(int player, T& target, +inline void ReplicatedInput::finalize_other(int player, T& target, octetStream& o) { typename T::value_type t; diff --git a/Processor/ReplicatedPrep.h b/Processor/ReplicatedPrep.h index 7b06c02..f482242 100644 --- a/Processor/ReplicatedPrep.h +++ b/Processor/ReplicatedPrep.h @@ -28,7 +28,7 @@ class BufferPrep : public Preprocessing virtual void buffer_inverses(MAC_Check_Base& MC, Player& P); public: - static const int buffer_size = 1000; + static const int buffer_size = 10000; virtual ~BufferPrep() {} @@ -49,6 +49,8 @@ class ReplicatedRingPrep : public BufferPrep typename T::Protocol* protocol; SubProcessor* proc; + int base_player; + void buffer_triples(); void buffer_squares(); void buffer_inverses() { throw runtime_error("not inverses in rings"); } @@ -57,7 +59,7 @@ class ReplicatedRingPrep : public BufferPrep ReplicatedRingPrep(SubProcessor* proc); virtual ~ReplicatedRingPrep() {} - void set_protocol(typename T::Protocol& protocol) { this->protocol = &protocol; } + void set_protocol(typename T::Protocol& protocol); virtual void buffer_bits(); }; diff --git a/Processor/ReplicatedPrep.hpp b/Processor/ReplicatedPrep.hpp index 19b7597..d8ac78c 100644 --- a/Processor/ReplicatedPrep.hpp +++ b/Processor/ReplicatedPrep.hpp @@ -15,6 +15,16 @@ ReplicatedRingPrep::ReplicatedRingPrep(SubProcessor* proc) : { } +template +void ReplicatedRingPrep::set_protocol(typename T::Protocol& protocol) +{ + this->protocol = &protocol; + if (proc) + base_player = proc->Proc.thread_num; + else + base_player = 0; +} + template void ReplicatedRingPrep::buffer_triples() { @@ -90,7 +100,7 @@ void BufferPrep::buffer_inverses(MAC_Check_Base& 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& res, vector& x, vector& 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 class T> void buffer_bits_spec(ReplicatedPrep>& prep, vector>& bits, typename T::Protocol& prot) { (void) bits, (void) prot; - if (get_n_relevant_players(prot.P) > 10) + if (prot.get_n_relevant_players() > 10) { vector, 2>> squares(prep.buffer_size); vector> s; @@ -189,12 +186,12 @@ void ReplicatedRingPrep::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> player_bits(n_relevant_players, vector(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::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 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>::buffer_bits() { assert(protocol != 0); diff --git a/Processor/SPDZ.cpp b/Processor/SPDZ.cpp deleted file mode 100644 index 8e5720b..0000000 --- a/Processor/SPDZ.cpp +++ /dev/null @@ -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; -template class SPDZ; diff --git a/Processor/Shamir.h b/Processor/Shamir.h index 9273579..206843d 100644 --- a/Processor/Shamir.h +++ b/Processor/Shamir.h @@ -19,7 +19,7 @@ template class ShamirInput; class Player; template -class Shamir : public PrepLessProtocol> +class Shamir : public ProtocolBase> { typedef ShamirShare T; @@ -45,6 +45,8 @@ class Shamir : public PrepLessProtocol> Shamir(Player& P); ~Shamir(); + int get_n_relevant_players(); + void reset(); void init_mul(SubProcessor* proc); diff --git a/Processor/Shamir.hpp b/Processor/Shamir.hpp index c82b7e9..4ee3651 100644 --- a/Processor/Shamir.hpp +++ b/Processor/Shamir.hpp @@ -5,7 +5,7 @@ #include "Shamir.h" #include "ShamirInput.h" -#include "ShamirMachine.h" +#include "Machines/ShamirMachine.h" template U Shamir::get_rec_factor(int i, int n) @@ -31,6 +31,12 @@ Shamir::~Shamir() delete resharing; } +template +int Shamir::get_n_relevant_players() +{ + return ShamirMachine::s().threshold + 1; +} + template void Shamir::reset() { diff --git a/Processor/ShamirInput.hpp b/Processor/ShamirInput.hpp index b548383..0674564 100644 --- a/Processor/ShamirInput.hpp +++ b/Processor/ShamirInput.hpp @@ -4,7 +4,7 @@ */ #include "ShamirInput.h" -#include "ShamirMachine.h" +#include "Machines/ShamirMachine.h" template void ShamirInput::reset(int player) diff --git a/Programs/Source/tutorial.mpc b/Programs/Source/tutorial.mpc index b9c84e6..f4ff0ed 100644 --- a/Programs/Source/tutorial.mpc +++ b/Programs/Source/tutorial.mpc @@ -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()) diff --git a/README.md b/README.md index 825ed8a..e6d49e2 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/Scripts/build.sh b/Scripts/build.sh new file mode 100755 index 0000000..95e91b1 --- /dev/null +++ b/Scripts/build.sh @@ -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 diff --git a/Scripts/gen_input_f2n.cpp b/Scripts/gen_input_f2n.cpp index bae1653..282aa68 100644 --- a/Scripts/gen_input_f2n.cpp +++ b/Scripts/gen_input_f2n.cpp @@ -1,7 +1,7 @@ #include #include #include "Math/gf2n.h" -#include "Processor/Buffer.h" +#include "Tools/Buffer.h" using namespace std; diff --git a/Scripts/gen_input_fp.cpp b/Scripts/gen_input_fp.cpp index ca87b9b..e258666 100644 --- a/Scripts/gen_input_fp.cpp +++ b/Scripts/gen_input_fp.cpp @@ -1,7 +1,7 @@ #include #include #include "Math/gfp.h" -#include "Processor/Buffer.h" +#include "Tools/Buffer.h" #include "Tools/ezOptionParser.h" #include "Math/Setup.h" diff --git a/Scripts/run-common.sh b/Scripts/run-common.sh index 870caba..4b6b50a 100644 --- a/Scripts/run-common.sh +++ b/Scripts/run-common.sh @@ -54,4 +54,4 @@ SPDZROOT=${SPDZROOT:-.} #. Scripts/setup.sh -mkdir logs +mkdir logs 2> /dev/null diff --git a/Scripts/setup-online.sh b/Scripts/setup-online.sh index 0b1cec8..b3176e6 100755 --- a/Scripts/setup-online.sh +++ b/Scripts/setup-online.sh @@ -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 diff --git a/Scripts/setup-ssl.sh b/Scripts/setup-ssl.sh index af98e27..4c2da68 100755 --- a/Scripts/setup-ssl.sh +++ b/Scripts/setup-ssl.sh @@ -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 diff --git a/Scripts/tldr.sh b/Scripts/tldr.sh new file mode 100755 index 0000000..91ea90b --- /dev/null +++ b/Scripts/tldr.sh @@ -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 diff --git a/Processor/Buffer.cpp b/Tools/Buffer.cpp similarity index 98% rename from Processor/Buffer.cpp rename to Tools/Buffer.cpp index 3389287..c8967fe 100644 --- a/Processor/Buffer.cpp +++ b/Tools/Buffer.cpp @@ -3,7 +3,7 @@ * */ -#include "Buffer.h" +#include "Tools/Buffer.h" bool BufferBase::rewind = false; diff --git a/Processor/Buffer.h b/Tools/Buffer.h similarity index 96% rename from Processor/Buffer.h rename to Tools/Buffer.h index 60c23a6..28f7d1c 100644 --- a/Processor/Buffer.h +++ b/Tools/Buffer.h @@ -3,8 +3,8 @@ * */ -#ifndef PROCESSOR_BUFFER_H_ -#define PROCESSOR_BUFFER_H_ +#ifndef TOOLS_BUFFER_H_ +#define TOOLS_BUFFER_H_ #include 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::input(U& a) next++; } -#endif /* PROCESSOR_BUFFER_H_ */ +#endif /* TOOLS_BUFFER_H_ */ diff --git a/Tools/aes-ni.cpp b/Tools/aes-ni.cpp index b88beec..3f678c3 100644 --- a/Tools/aes-ni.cpp +++ b/Tools/aes-ni.cpp @@ -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 diff --git a/Tools/aes.h b/Tools/aes.h index 5229717..799f5c4 100644 --- a/Tools/aes.h +++ b/Tools/aes.h @@ -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 diff --git a/Tools/octetStream.cpp b/Tools/octetStream.cpp index 978b796..b0e9b6e 100644 --- a/Tools/octetStream.cpp +++ b/Tools/octetStream.cpp @@ -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 diff --git a/Tools/random.cpp b/Tools/random.cpp index c442502..d45a2b3 100644 --- a/Tools/random.cpp +++ b/Tools/random.cpp @@ -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() diff --git a/Tools/random.h b/Tools/random.h index 27760c3..48ad687 100644 --- a/Tools/random.h +++ b/Tools/random.h @@ -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 diff --git a/Yao/Program.cpp b/Yao/Program.cpp index 384c787..9302ac3 100644 --- a/Yao/Program.cpp +++ b/Yao/Program.cpp @@ -9,6 +9,8 @@ #include "GC/Instruction.hpp" #include "GC/Program.hpp" +#include "Processor/Instruction.hpp" + namespace GC { diff --git a/Yao/YaoGarbler.h b/Yao/YaoGarbler.h index 3271d41..ea87447 100644 --- a/Yao/YaoGarbler.h +++ b/Yao/YaoGarbler.h @@ -15,7 +15,8 @@ #include "GC/Secret.h" #include "Networking/Player.h" #include "OT/OTExtensionWithMatrix.h" -#include "sys/sysinfo.h" + +#include using namespace GC; @@ -66,7 +67,8 @@ class YaoGarbler : public GC::Thread>, public YaoCommo 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); } diff --git a/bin/README.md b/bin/README.md new file mode 100644 index 0000000..59be803 --- /dev/null +++ b/bin/README.md @@ -0,0 +1,13 @@ +In binary releases, this directory constains statically linked +binaries. They included code from the following projects, whose licenses +are thus provided in separate files: +- Boost +- glibc +- libsodium +- MPIR +- OpenSSl + +The binaries also include code from libstdc++ and libgcc. They have +been produced using `Scripts/build.sh` and standard GCC from +Devtoolset-6 on CentOS 6 and therefore satisfy the [GCC Runtime Library +Exception](https://www.gnu.org/licenses/gcc-exception-3.1.en.html). diff --git a/bin/boost-license.txt b/bin/boost-license.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/bin/boost-license.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bin/glibc-license.txt b/bin/glibc-license.txt new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/bin/glibc-license.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/bin/libsodium-license.txt b/bin/libsodium-license.txt new file mode 100644 index 0000000..62510f3 --- /dev/null +++ b/bin/libsodium-license.txt @@ -0,0 +1,18 @@ +/* + * ISC License + * + * Copyright (c) 2013-2019 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/bin/mpir-license.txt b/bin/mpir-license.txt new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/bin/mpir-license.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/bin/openssl-license.txt b/bin/openssl-license.txt new file mode 100644 index 0000000..0511f2e --- /dev/null +++ b/bin/openssl-license.txt @@ -0,0 +1,125 @@ + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + diff --git a/malicious-shamir-party.cpp b/malicious-shamir-party.cpp index 39e7856..b4f2705 100644 --- a/malicious-shamir-party.cpp +++ b/malicious-shamir-party.cpp @@ -3,7 +3,7 @@ * */ -#include "Processor/ShamirMachine.h" +#include "Machines/ShamirMachine.h" #include "Math/MaliciousShamirShare.h" int main(int argc, const char** argv) diff --git a/shamir-party.cpp b/shamir-party.cpp index db9dd48..7e33b2a 100644 --- a/shamir-party.cpp +++ b/shamir-party.cpp @@ -3,7 +3,7 @@ * */ -#include "Processor/ShamirMachine.h" +#include "Machines/ShamirMachine.h" #include "Math/ShamirShare.h" int main(int argc, const char** argv)