Browse Source

moving 2-party precossing with OT extension

avadapal 1 year ago
parent
commit
60d125065d
74 changed files with 10387 additions and 0 deletions
  1. 857 0
      2p-preprocessing/ENCRYPTO_utils/cbitvector.cpp
  2. 717 0
      2p-preprocessing/ENCRYPTO_utils/cbitvector.h
  3. 163 0
      2p-preprocessing/ENCRYPTO_utils/channel.cpp
  4. 78 0
      2p-preprocessing/ENCRYPTO_utils/channel.h
  5. 53 0
      2p-preprocessing/ENCRYPTO_utils/circular_queue.cpp
  6. 38 0
      2p-preprocessing/ENCRYPTO_utils/circular_queue.h
  7. 302 0
      2p-preprocessing/ENCRYPTO_utils/codewords.cpp
  8. 36 0
      2p-preprocessing/ENCRYPTO_utils/codewords.h
  9. 117 0
      2p-preprocessing/ENCRYPTO_utils/connection.cpp
  10. 39 0
      2p-preprocessing/ENCRYPTO_utils/connection.h
  11. 66 0
      2p-preprocessing/ENCRYPTO_utils/constants.h
  12. 41 0
      2p-preprocessing/ENCRYPTO_utils/crypto/Config.h
  13. 576 0
      2p-preprocessing/ENCRYPTO_utils/crypto/TedKrovetzAesNiWrapperC.cpp
  14. 85 0
      2p-preprocessing/ENCRYPTO_utils/crypto/TedKrovetzAesNiWrapperC.h
  15. 489 0
      2p-preprocessing/ENCRYPTO_utils/crypto/crypto.cpp
  16. 150 0
      2p-preprocessing/ENCRYPTO_utils/crypto/crypto.h
  17. 809 0
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk.cpp
  18. 143 0
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk.h
  19. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_16.bin
  20. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_32.bin
  21. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_64.bin
  22. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_8.bin
  23. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_16.bin
  24. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_32.bin
  25. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_64.bin
  26. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_8.bin
  27. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_16.bin
  28. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_32.bin
  29. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_64.bin
  30. BIN
      2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_8.bin
  31. 357 0
      2p-preprocessing/ENCRYPTO_utils/crypto/djn.cpp
  32. 176 0
      2p-preprocessing/ENCRYPTO_utils/crypto/djn.h
  33. 442 0
      2p-preprocessing/ENCRYPTO_utils/crypto/ecc-pk-crypto.cpp
  34. 141 0
      2p-preprocessing/ENCRYPTO_utils/crypto/ecc-pk-crypto.h
  35. 35 0
      2p-preprocessing/ENCRYPTO_utils/crypto/gmp-pk-crypto.cpp
  36. 143 0
      2p-preprocessing/ENCRYPTO_utils/crypto/gmp-pk-crypto.h
  37. 354 0
      2p-preprocessing/ENCRYPTO_utils/crypto/intrin_sequential_enc8.cpp
  38. 58 0
      2p-preprocessing/ENCRYPTO_utils/crypto/intrin_sequential_enc8.h
  39. 114 0
      2p-preprocessing/ENCRYPTO_utils/crypto/pk-crypto.h
  40. 144 0
      2p-preprocessing/ENCRYPTO_utils/parse_options.cpp
  41. 76 0
      2p-preprocessing/ENCRYPTO_utils/parse_options.h
  42. 175 0
      2p-preprocessing/ENCRYPTO_utils/powmod.cpp
  43. 57 0
      2p-preprocessing/ENCRYPTO_utils/powmod.h
  44. 170 0
      2p-preprocessing/ENCRYPTO_utils/rcvthread.cpp
  45. 76 0
      2p-preprocessing/ENCRYPTO_utils/rcvthread.h
  46. 158 0
      2p-preprocessing/ENCRYPTO_utils/sndthread.cpp
  47. 73 0
      2p-preprocessing/ENCRYPTO_utils/sndthread.h
  48. 264 0
      2p-preprocessing/ENCRYPTO_utils/socket.cpp
  49. 68 0
      2p-preprocessing/ENCRYPTO_utils/socket.h
  50. 98 0
      2p-preprocessing/ENCRYPTO_utils/thread.cpp
  51. 75 0
      2p-preprocessing/ENCRYPTO_utils/thread.h
  52. 124 0
      2p-preprocessing/ENCRYPTO_utils/timer.cpp
  53. 107 0
      2p-preprocessing/ENCRYPTO_utils/timer.h
  54. 77 0
      2p-preprocessing/ENCRYPTO_utils/typedefs.h
  55. 125 0
      2p-preprocessing/ENCRYPTO_utils/utils.cpp
  56. 66 0
      2p-preprocessing/ENCRYPTO_utils/utils.h
  57. 48 0
      2p-preprocessing/Makefile
  58. 1 0
      2p-preprocessing/X0.txt
  59. 1 0
      2p-preprocessing/X1.txt
  60. 1 0
      2p-preprocessing/Y0.txt
  61. 1 0
      2p-preprocessing/Y1.txt
  62. 152 0
      2p-preprocessing/aes.h
  63. 202 0
      2p-preprocessing/bitutils.h
  64. 185 0
      2p-preprocessing/block.h
  65. 1 0
      2p-preprocessing/gamma0.txt
  66. 1 0
      2p-preprocessing/gamma1.txt
  67. 48 0
      2p-preprocessing/mpc.h
  68. 397 0
      2p-preprocessing/ot_blinds.cpp
  69. 73 0
      2p-preprocessing/ot_blinds.h
  70. BIN
      2p-preprocessing/party0_read_flags_b
  71. BIN
      2p-preprocessing/party1_read_flags_b
  72. 671 0
      2p-preprocessing/preprocessing.cpp
  73. 20 0
      2p-preprocessing/prg.h
  74. 73 0
      2p-preprocessing/prg_aes_impl.h

+ 857 - 0
2p-preprocessing/ENCRYPTO_utils/cbitvector.cpp

@@ -0,0 +1,857 @@
+/**
+ \file 		cbitvector.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		CBitVector Implementation
+ */
+
+#include "cbitvector.h"
+#include "crypto/crypto.h"
+#include "utils.h"
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <cstring>
+
+
+namespace {
+
+/** Array which stores the bytes which are reversed. For example, the hexadecimal 0x01 is when reversed becomes 0x80.  */
+constexpr BYTE REVERSE_BYTE_ORDER[256] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8,
+		0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C,
+		0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
+		0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96,
+		0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1,
+		0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85,
+		0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD,
+		0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B,
+		0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF,
+		0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF };
+
+/**
+	This array is used by \link XORBits(BYTE* p, int pos, int len) \endlink and \link SetBits(BYTE* p, uint64_t pos, uint64_t len) \endlink
+    method for lower bit mask.
+*/
+constexpr BYTE RESET_BIT_POSITIONS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
+/**
+	This array is used by \link XORBits(BYTE* p, int pos, int len) \endlink and \link SetBits(BYTE* p, uint64_t pos, uint64_t len) \endlink
+    method for upper bit mask.
+*/
+constexpr BYTE RESET_BIT_POSITIONS_INV[9] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
+
+/** This array is used by \link GetBits(BYTE* p, int pos, int len) \endlink method for lower bit mask. */
+constexpr BYTE GET_BIT_POSITIONS[9] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00 };
+
+/** This array is used by \link GetBits(BYTE* p, int pos, int len) \endlink method for upper bit mask. */
+constexpr BYTE GET_BIT_POSITIONS_INV[9] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00 };
+
+/**
+	This array is used for masking bits and extracting a particular positional bit from the provided byte array.
+	This array is used by \link GetBit(int idx) \endlink method.
+*/
+constexpr BYTE MASK_BIT[8] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
+
+/**
+	This array is used for extracting a particular positional bit from the provided byte array without masking.
+	This array is used by \link GetBitNoMask(int idx) \endlink method.
+*/
+static constexpr BYTE BIT[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
+
+/**
+	This array is used for masking bits and setting a particular positional bit from the provided byte array in the CBitVector.
+	This array is used by \link SetBit(int idx, BYTE b) \endlink and \link ANDBit(int idx, BYTE b) \endlink methods.
+*/
+constexpr BYTE CMASK_BIT[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
+
+/**
+	This array is used for setting a particular positional bit from the provided byte array without masking in the CBitVector.
+	This array is used by \link SetBitNoMask(int idx, BYTE b) \endlink and \link ANDBitNoMask(int idx, BYTE b) \endlink methods.
+*/
+constexpr BYTE C_BIT[8] = { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F };
+
+/**
+	This array is used for masking bits and setting a particular positional bit from the provided byte array in the CBitVector.
+	This array is used by \link SetBit(int idx, BYTE b) \endlink and \link XORBit(int idx, BYTE b) \endlink methods.
+*/
+constexpr BYTE MASK_SET_BIT_C[2][8] = { { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }, { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+/**
+	This array is used for setting a particular positional bit from the provided byte array without masking in the CBitVector.
+	This array is used by \link SetBitNoMask(int idx, BYTE b) \endlink and \link XORBitNoMask(int idx, BYTE b) \endlink methods.
+*/
+constexpr BYTE SET_BIT_C[2][8] = { { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }, { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+const BYTE SELECT_BIT_POSITIONS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
+
+#if (__WORDSIZE==32)
+constexpr REGISTER_SIZE TRANSPOSITION_MASKS[6] =
+{	0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};
+constexpr REGISTER_SIZE TRANSPOSITION_MASKS_INV[6] =
+{	0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000};
+#else
+#if (__WORDSIZE==64)
+/** Transposition mask used for Eklund Bit Matrix Transposition.*/
+constexpr REGISTER_SIZE TRANSPOSITION_MASKS[6] = { 0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF };
+constexpr REGISTER_SIZE TRANSPOSITION_MASKS_INV[6] = { 0xAAAAAAAAAAAAAAAA, 0xCCCCCCCCCCCCCCCC, 0xF0F0F0F0F0F0F0F0, 0xFF00FF00FF00FF00, 0xFFFF0000FFFF0000, 0xFFFFFFFF00000000 };
+#else
+#endif
+#endif
+
+constexpr size_t SHIFTVAL = 3;
+
+
+template<class T> void GetBytes(T* dst, const T* src, const T* lim) {
+	while (dst != lim) {
+		*dst++ = *src++;
+	}
+}
+
+template<class T> void SetBytes(T* dst, const T* src, const T* lim) {
+	while (dst < lim) {
+		*dst++ = *src++;
+	}
+}
+
+//Generic bytewise XOR operation
+template<class T> void XORBytes(T* dst, const T* src, const T* lim) {
+	while (dst != lim) {
+		*dst++ ^= *src++;
+	}
+}
+
+template<class T> void ANDBytes(T* dst, const T* src, const T* lim) {
+	while (dst != lim) {
+		*dst++ &= *src++;
+	}
+}
+
+constexpr BYTE GetArrayBit(const BYTE* p, size_t idx) {
+	return 0 != (p[idx >> 3] & BIT[idx & 0x7]);
+}
+
+} // namespace
+
+
+CBitVector::CBitVector() {
+	Init();
+}
+
+CBitVector::CBitVector(std::size_t bits) {
+	Init();
+	Create(bits);
+}
+
+CBitVector::CBitVector(std::size_t bits, crypto* crypt) {
+	Init();
+	Create(bits, crypt);
+}
+
+void CBitVector::Init() {
+	m_pBits = NULL;
+	m_nByteSize = 0;
+}
+
+CBitVector::~CBitVector(){
+	delCBitVector();
+};
+
+void CBitVector::delCBitVector() {
+	if (( m_nByteSize > 0 )&& (m_pBits != NULL)) {
+		free(m_pBits);
+	}
+	m_nByteSize = 0;
+	m_pBits = NULL;
+}
+
+/* Fill random values using the pre-defined AES key */
+void CBitVector::FillRand(std::size_t bits, crypto* crypt) {
+	if (bits > m_nByteSize << 3)
+		Create(bits);
+	crypt->gen_rnd(m_pBits, ceil_divide(bits, 8));
+}
+
+void CBitVector::CreateExact(std::size_t bits) {
+	if (bits == 0){
+		bits = AES_BITS;
+	}
+
+	// if memory was previously allocated: free it
+	if (m_nByteSize > 0) {
+		free(m_pBits);
+	}
+
+	m_nByteSize = ceil_divide(bits, 8);
+	m_pBits = (BYTE*) calloc(m_nByteSize, sizeof(BYTE));
+	assert(m_pBits != NULL);
+
+	m_nElementLength = 1;
+	m_nNumElements = m_nByteSize;
+	m_nNumElementsDimB = 1;
+}
+
+void CBitVector::Create(std::size_t bits) {
+	//TODO: check if padding to AES_BITS is still necessary as default
+	CreateExact(ceil_divide(bits, AES_BITS) * AES_BITS);
+}
+
+void CBitVector::CreateBytes(std::size_t bytes) {
+	Create(bytes << 3);
+}
+
+void CBitVector::CreateBytes(std::size_t bytes, crypto* crypt) {
+	Create(bytes << 3, crypt);
+}
+
+void CBitVector::CreateZeros(std::size_t bits) {
+	Create(bits);
+	memset(m_pBits, 0, m_nByteSize);
+}
+
+void CBitVector::Create(std::size_t bits, crypto* crypt) {
+	Create(bits);
+	FillRand(bits, crypt);
+}
+
+void CBitVector::Create(std::size_t numelements, std::size_t elementlength) {
+	Create(numelements * elementlength);
+	m_nElementLength = elementlength;
+	m_nNumElements = numelements;
+	m_nNumElementsDimB = 1;
+}
+
+void CBitVector::Create(std::size_t numelements, std::size_t elementlength, crypto* crypt) {
+	Create(numelements * elementlength, crypt);
+	m_nElementLength = elementlength;
+	m_nNumElements = numelements;
+	m_nNumElementsDimB = 1;
+}
+
+void CBitVector::Create(std::size_t numelementsDimA, std::size_t numelementsDimB, std::size_t elementlength) {
+	Create(numelementsDimA * numelementsDimB * elementlength);
+	m_nElementLength = elementlength;
+	m_nNumElements = numelementsDimA;
+	m_nNumElementsDimB = numelementsDimB;
+}
+void CBitVector::Create(std::size_t numelementsDimA, std::size_t numelementsDimB, std::size_t elementlength, crypto* crypt) {
+	Create(numelementsDimA * numelementsDimB * elementlength, crypt);
+	m_nElementLength = elementlength;
+	m_nNumElements = numelementsDimA;
+	m_nNumElementsDimB = numelementsDimB;
+}
+
+void CBitVector::ResizeinBytes(std::size_t newSizeBytes) {
+	BYTE* tBits = m_pBits;
+	uint64_t tSize = (m_nByteSize<newSizeBytes)? m_nByteSize:newSizeBytes; //fix for overflow condition in memcpy.
+
+	m_nByteSize = newSizeBytes;
+	m_pBits = (uint8_t*) calloc(m_nByteSize, sizeof(uint8_t));
+
+	memcpy(m_pBits, tBits, tSize);
+
+	free(tBits);
+}
+
+void CBitVector::Reset() {
+	memset(m_pBits, 0, m_nByteSize);
+}
+
+void CBitVector::ResetFromTo(std::size_t frombyte, std::size_t tobyte) {
+	assert(frombyte <= tobyte);
+	assert(tobyte < m_nByteSize);
+	memset(m_pBits + frombyte, 0, tobyte - frombyte);
+}
+
+void CBitVector::SetToOne() {
+	memset(m_pBits, 0xFF, m_nByteSize);
+}
+
+void CBitVector::Invert() {
+	for(std::size_t i = 0; i < m_nByteSize; i++) {
+		m_pBits[i] = ~m_pBits[i];
+	}
+}
+
+std::size_t CBitVector::GetSize() const {
+	return m_nByteSize;
+}
+
+BOOL CBitVector::IsEqual(const CBitVector& vec) const {
+	if (vec.GetSize() != m_nByteSize) {
+		return false;
+	}
+
+	const BYTE* ptr = vec.GetArr();
+	for (std::size_t i = 0; i < m_nByteSize; i++) {
+		if (ptr[i] != m_pBits[i]) {
+			return false;
+		}
+	}
+	return true;
+}
+
+BOOL CBitVector::IsEqual(const CBitVector& vec, std::size_t from, std::size_t to) const {
+	if (vec.GetSize() * 8 < to || m_nByteSize * 8 < to || from > to) {
+		return false;
+	}
+
+	for (std::size_t i = from; i < to; i++) {
+		if (vec.GetBit(i) != GetBit(i)) {
+			return false;
+		}
+	}
+	return true;
+}
+
+void CBitVector::SetElementLength(std::size_t elelen) {
+	m_nElementLength = elelen;
+}
+
+std::size_t CBitVector::GetElementLength() const {
+	return m_nElementLength;
+}
+
+void CBitVector::Copy(const CBitVector& vec) {
+	Copy(vec.GetArr(), 0, vec.GetSize());
+}
+
+void CBitVector::Copy(const CBitVector& vec, std::size_t pos, std::size_t len) {
+	Copy(vec.GetArr(), pos, len);
+}
+
+void CBitVector::Copy(const BYTE* p, std::size_t pos, std::size_t len) {
+	if (pos + len > m_nByteSize) {
+		if (m_pBits)
+			ResizeinBytes(pos + len);
+		else {
+			CreateBytes(pos + len);
+		}
+	}
+	memcpy(m_pBits + pos, p, len);
+}
+
+void CBitVector::ORByte(std::size_t pos, BYTE p) {
+	assert(pos <= m_nByteSize);
+	m_pBits[pos] |= p;
+}
+
+BYTE CBitVector::GetBit(std::size_t idx) const {
+	assert(idx < (m_nByteSize << 3));
+	return !!(m_pBits[idx >> 3] & MASK_BIT[idx & 0x7]);
+}
+
+void CBitVector::SetBit(std::size_t idx, BYTE b) {
+	assert(idx < (m_nByteSize << 3));
+	m_pBits[idx >> 3] = (m_pBits[idx >> 3] & CMASK_BIT[idx & 0x7]) | MASK_SET_BIT_C[!(b & 0x01)][idx & 0x7];
+}
+
+BYTE CBitVector::GetBitNoMask(std::size_t idx) const {
+	assert(idx < (m_nByteSize << 3));
+	return GetArrayBit(m_pBits, idx);
+}
+
+void CBitVector::SetBitNoMask(std::size_t idx, BYTE b) {
+	assert(idx < (m_nByteSize << 3));
+	m_pBits[idx >> 3] = (m_pBits[idx >> 3] & C_BIT[idx & 0x7]) | SET_BIT_C[!(b & 0x01)][idx & 0x7];
+}
+
+void CBitVector::XORBitNoMask(std::size_t idx, BYTE b) {
+	assert(idx < (m_nByteSize << 3));
+	m_pBits[idx >> 3] ^= SET_BIT_C[!(b & 0x01)][idx & 0x7];
+}
+
+void CBitVector::SetByte(std::size_t idx, BYTE p) {
+	assert(idx < m_nByteSize);
+	m_pBits[idx] = p;
+}
+
+BYTE CBitVector::GetByte(std::size_t idx) const {
+	assert(idx < m_nByteSize);
+	return m_pBits[idx];
+}
+
+void CBitVector::XORByte(std::size_t idx, BYTE b) {
+	assert(idx < m_nByteSize);
+	m_pBits[idx] ^= b;
+}
+
+void CBitVector::ANDByte(std::size_t idx, BYTE b) {
+	assert(idx < m_nByteSize);
+	m_pBits[idx] &= b;
+}
+
+void CBitVector::GetBits(BYTE* p, std::size_t pos, std::size_t len) const {
+	if (len < 1 || (pos + len) > (m_nByteSize << 3)) {
+		return;
+	}
+	if (len == 1) {
+		*p = GetBitNoMask(pos);
+		return;
+	}
+
+	if (!((pos & 0x07) || (len & 0x07))) {
+		GetBytes(p, pos >> 3, len >> 3);
+		return;
+	}
+
+	int posctr = pos >> 3;
+	int lowermask = pos & 7;
+	int uppermask = 8 - lowermask;
+
+	std::size_t i;
+	for (i = 0; i < len / (sizeof(BYTE) * 8); i++, posctr++) {
+		p[i] = ((m_pBits[posctr] & GET_BIT_POSITIONS[lowermask]) >> lowermask) & 0xFF;
+		p[i] |= (m_pBits[posctr + 1] & GET_BIT_POSITIONS_INV[uppermask]) << uppermask;
+	}
+	int remlen = len & 0x07;
+	if (remlen) {
+		if (remlen <= uppermask) {
+			p[i] = ((m_pBits[posctr] & ((((1 << remlen) - 1) << lowermask))) >> lowermask) & 0xFF;
+		} else {
+			p[i] = ((m_pBits[posctr] & GET_BIT_POSITIONS[lowermask]) >> lowermask) & 0xFF;
+			p[i] |= (m_pBits[posctr + 1] & (((1 << (remlen - uppermask)) - 1))) << uppermask;
+		}
+	}
+}
+
+
+//optimized bytewise for set operation
+void CBitVector::GetBytes(BYTE* p, std::size_t pos, std::size_t len) const {
+	assert(pos+len <= m_nByteSize);
+	BYTE* src = m_pBits + pos;
+	BYTE* dst = p;
+	//Do many operations on REGSIZE types first and then (if necessary) use bytewise operations
+	::GetBytes((REGSIZE*) dst, (REGSIZE*) src, ((REGSIZE*) dst) + (len >> SHIFTVAL));
+	dst += ((len >> SHIFTVAL) << SHIFTVAL);
+	src += ((len >> SHIFTVAL) << SHIFTVAL);
+	::GetBytes(dst, src, dst + (len & ((1 << SHIFTVAL) - 1)));
+}
+//
+//pos and len in bits
+void CBitVector::SetBits(const BYTE* p, std::size_t pos, std::size_t len) {
+	if (len < 1 || (pos + len) > (m_nByteSize << 3)){
+		return;
+	}
+
+	if (len == 1) {
+		SetBitNoMask(pos, *p);
+		return;
+	}
+	if (!((pos & 0x07) || (len & 0x07))) {
+
+		SetBytes(p, pos >> 3, len >> 3);
+		return;
+	}
+	std::size_t posctr = pos >> 3;
+	int lowermask = pos & 7;
+	int uppermask = 8 - lowermask;
+
+	std::size_t i;
+	BYTE temp;
+	for (i = 0; i < len / (sizeof(BYTE) * 8); i++, posctr++) {
+		temp = p[i];
+		m_pBits[posctr] = (m_pBits[posctr] & RESET_BIT_POSITIONS[lowermask]) | ((temp << lowermask) & 0xFF);
+		m_pBits[posctr + 1] = (m_pBits[posctr + 1] & RESET_BIT_POSITIONS_INV[uppermask]) | (temp >> uppermask);
+	}
+	int remlen = len & 0x07;
+	if (remlen) {
+		temp = p[i] & RESET_BIT_POSITIONS[remlen];
+		if (remlen <= uppermask) {
+			m_pBits[posctr] = (m_pBits[posctr] & (~(((1 << remlen) - 1) << lowermask))) | ((temp << lowermask) & 0xFF);
+		} else {
+			m_pBits[posctr] = (m_pBits[posctr] & RESET_BIT_POSITIONS[lowermask]) | ((temp << lowermask) & 0xFF);
+			m_pBits[posctr + 1] = (m_pBits[posctr + 1] & (~(((1 << (remlen - uppermask)) - 1)))) | (temp >> uppermask);
+		}
+	}
+}
+
+
+//Set bits given an offset on the bits for p which is not necessarily divisible by 8
+void CBitVector::SetBitsPosOffset(const BYTE* p, std::size_t ppos, std::size_t pos, std::size_t len) {
+	for (auto i = pos, j = ppos; j < ppos + len; i++, j++) {
+		BYTE source_bit = GetArrayBit(p, j);
+		SetBitNoMask(i, source_bit);
+
+	}
+}
+
+//optimized bytewise for set operation
+void CBitVector::SetBytes(const BYTE *src, std::size_t pos, std::size_t len) {
+	assert(pos + len <= m_nByteSize);
+
+	BYTE *dst = m_pBits + pos;
+
+	//Do many operations on REGSIZE types first and then (if necessary) use bytewise operations
+	::SetBytes((REGSIZE*) dst, (REGSIZE*) src, ((REGSIZE*) dst) + (len >> SHIFTVAL));
+	dst += ((len >> SHIFTVAL) << SHIFTVAL);
+	src += ((len >> SHIFTVAL) << SHIFTVAL);
+	::SetBytes(dst, src, dst + (len & ((1 << SHIFTVAL) - 1)));
+}
+
+void CBitVector::SetBytesToZero(std::size_t bytepos, std::size_t bytelen) {
+	assert(bytepos + bytelen <= m_nByteSize);
+	memset(m_pBits + bytepos, 0x00, bytelen);
+}
+
+
+void CBitVector::SetBitsToZero(std::size_t bitpos, std::size_t bitlen) {
+	int firstlim = ceil_divide(bitpos, 8);
+	int firstlen = ceil_divide(bitlen - (bitpos % 8), 8);
+	for (int i = bitpos; i < firstlim; i++) {
+		SetBitNoMask(i, 0);
+	}
+	if (bitlen > 7) {
+		memset(m_pBits + firstlim, 0, firstlen);
+	}
+	for (std::size_t i = (firstlim + firstlen) << 8; i < bitpos + bitlen; i++) {
+		SetBitNoMask(i, 0);
+	}
+}
+
+//optimized bytewise XOR operation
+void CBitVector::XORBytes(const BYTE* p, std::size_t pos, std::size_t len) {
+	if(pos + len > m_nByteSize)
+	std::cout << "pos = " << pos << ", len = " << len << ", bytesize = " << m_nByteSize << std::endl;
+	assert(pos + len <= m_nByteSize);
+
+	BYTE* dst = m_pBits + pos;
+	const BYTE* src = p;
+	//Do many operations on REGSIZE types first and then (if necessary) use bytewise operations
+	::XORBytes((REGSIZE*) dst, (REGSIZE*) src, ((REGSIZE*) dst) + (len >> SHIFTVAL));
+	dst += ((len >> SHIFTVAL) << SHIFTVAL);
+	src += ((len >> SHIFTVAL) << SHIFTVAL);
+	::XORBytes(dst, src, dst + (len & ((1 << SHIFTVAL) - 1)));
+}
+
+void CBitVector::XORBytes(const BYTE* p, std::size_t len) {
+	XORBytes(p, 0, len);
+}
+
+void CBitVector::XORVector(const CBitVector &vec, std::size_t pos, std::size_t len) {
+	XORBytes(vec.GetArr(), pos, len);
+}
+
+void CBitVector::XORBits(const BYTE* p, std::size_t pos, std::size_t len) {
+	if (len < 1 || (pos + len) > m_nByteSize << 3) {
+		return;
+	}
+	if (len == 1) {
+		XORBitNoMask(pos, *p);
+		return;
+	}
+	if (!((pos & 0x07) || (len & 0x07))) {
+		XORBytes(p, pos >> 3, len >> 3);
+		return;
+	}
+	int posctr = pos >> 3;
+	int lowermask = pos & 7;
+	int uppermask = 8 - lowermask;
+
+	std::size_t i;
+	BYTE temp;
+	for (i = 0; i < len / (sizeof(BYTE) * 8); i++, posctr++) {
+		temp = p[i];
+		m_pBits[posctr] ^= ((temp << lowermask) & 0xFF);
+		m_pBits[posctr + 1] ^= (temp >> uppermask);
+	}
+	int remlen = len & 0x07;
+	if (remlen) {
+		temp = p[i] & RESET_BIT_POSITIONS[remlen];
+		if (remlen <= uppermask) {
+			m_pBits[posctr] ^= ((temp << lowermask) & 0xFF);
+		} else {
+			m_pBits[posctr] ^= ((temp << lowermask) & 0xFF);
+			m_pBits[posctr + 1] ^= (temp >> uppermask);
+		}
+	}
+}
+
+//XOR bits given an offset on the bits for p which is not necessarily divisible by 8
+void CBitVector::XORBitsPosOffset(const BYTE* p, std::size_t ppos, std::size_t pos, std::size_t len) {
+	assert((pos + len) <= (m_nByteSize<<3));
+	for (auto i = pos, j = ppos; j < ppos + len; i++, j++) {
+		m_pBits[i / 8] ^= (((p[j / 8] & (1 << (j % 8))) >> j % 8) << i % 8);
+	}
+}
+
+//Method for directly XORing CBitVectors
+void CBitVector::XOR(const CBitVector* b) {
+	assert(b->GetSize() == m_nByteSize);
+	XORBytes(b->GetArr(), 0, m_nByteSize);
+}
+
+void CBitVector::XORBytesReverse(const BYTE* p, std::size_t pos, std::size_t len) {
+	assert((pos + len) <= m_nByteSize);
+	const BYTE* src = p;
+	BYTE* dst = m_pBits + pos;
+	BYTE* lim = dst + len;
+	while (dst != lim) {
+		*dst++ ^= REVERSE_BYTE_ORDER[*src++];
+	}
+}
+
+
+//optimized bytewise for AND operation
+void CBitVector::ANDBytes(const BYTE* p, std::size_t pos, std::size_t len) {
+	assert(pos+len <= m_nByteSize);
+	BYTE* dst = m_pBits + pos;
+	const BYTE* src = p;
+	//Do many operations on REGSIZE types first and then (if necessary) use bytewise operations
+	::ANDBytes((REGSIZE*) dst, (REGSIZE*) src, ((REGSIZE*) dst) + (len >> SHIFTVAL));
+	dst += ((len >> SHIFTVAL) << SHIFTVAL);
+	src += ((len >> SHIFTVAL) << SHIFTVAL);
+	::ANDBytes(dst, src, dst + (len & ((1 << SHIFTVAL) - 1)));
+}
+
+void CBitVector::SetXOR(const BYTE* p, const BYTE* q, std::size_t pos, std::size_t len) {
+	Copy(p, pos, len);
+	XORBytes(q, pos, len);
+}
+
+void CBitVector::SetAND(const BYTE* p, const BYTE* q, std::size_t pos, std::size_t len) {
+	Copy(p, pos, len);
+	ANDBytes(q, pos, len);
+}
+
+//Method for directly ANDing CBitVectors
+void CBitVector::AND(const CBitVector* b) {
+	assert(b->GetSize() == m_nByteSize);
+	ANDBytes(b->GetArr(), 0, m_nByteSize);
+}
+
+//Cyclic left shift by pos bits
+void CBitVector::CLShift(std::size_t pos) {
+	uint8_t* tmpbuf = (uint8_t*) malloc(m_nByteSize);
+	for(std::size_t i = 0; i < m_nByteSize; i++) {
+		tmpbuf[i+pos] = m_pBits[i];
+	}
+	free(m_pBits);
+	m_pBits = tmpbuf;
+}
+
+BYTE* CBitVector::GetArr() {
+	return m_pBits;
+}
+
+const BYTE* CBitVector::GetArr() const {
+	return m_pBits;
+}
+
+void CBitVector::AttachBuf(BYTE* p, std::size_t size) {
+	m_pBits = p;
+	m_nByteSize = size;
+}
+
+
+/**
+	This method is used to detach the buffer from the CBitVector. */
+void CBitVector::DetachBuf() {
+	m_pBits = NULL;
+	m_nByteSize = 0;
+}
+
+
+void CBitVector::Print(std::size_t fromBit, std::size_t toBit) {
+	std::size_t to = toBit > (m_nByteSize << 3) ? (m_nByteSize << 3) : toBit;
+
+	std::cout << "fromBit = " << fromBit << std::endl;
+	std::cout << "to 	  = " << to << std::endl;
+	for (std::size_t i = fromBit; i < to; i++) {
+		std::cout << (unsigned int) GetBitNoMask(i);
+	}
+	std::cout << std::endl;
+}
+
+void CBitVector::PrintHex(bool linebreak) {
+	for (std::size_t i = 0; i < m_nByteSize; i++) {
+		std::cout << std::setw(2) << std::setfill('0') << (std::hex) << ((unsigned int) m_pBits[i]);
+	}
+	if(linebreak){
+		std::cout << (std::dec) << std::endl;
+	}
+}
+
+void CBitVector::PrintHex(std::size_t fromByte, std::size_t toByte, bool linebreak) {
+	std::size_t to = toByte > (m_nByteSize) ? (m_nByteSize) : toByte;
+
+	for (std::size_t i = fromByte; i < to; i++) {
+		std::cout << std::setw(2) << std::setfill('0') << (std::hex) << ((unsigned int) m_pBits[i]);
+	}
+	if(linebreak){
+		std::cout << (std::dec) << std::endl;
+	}
+}
+
+void CBitVector::PrintBinary() {
+	std::cout << "PRINT BINARY:: " << std::endl;
+	Print(0, m_nByteSize << 3);
+}
+
+void CBitVector::PrintContent() {
+	if (m_nElementLength == 1) {
+		PrintHex();
+		return;
+	}
+	if (m_nNumElementsDimB == 1) {
+		for (std::size_t i = 0; i < m_nNumElements; i++) {
+			std::cout << Get<int>(i) << ", ";
+		}
+		std::cout << std::endl;
+	} else {
+		for (std::size_t i = 0; i < m_nNumElements; i++) {
+			std::cout << "(";
+			for (std::size_t j = 0; j < m_nNumElementsDimB - 1; j++) {
+				std::cout << Get2D<int>(i, j) << ", ";
+			}
+			std::cout << Get2D<int>(i, m_nNumElementsDimB - 1);
+			std::cout << "), ";
+		}
+		std::cout << std::endl;
+	}
+}
+
+void CBitVector::PrintBinaryMasked(std::size_t from, std::size_t to) {
+	std::size_t new_to = to > (m_nByteSize<<3) ? (m_nByteSize<<3) : to;
+
+	for (std::size_t i = from; i < new_to; i++) {
+		std::cout << (unsigned int) GetBit(i);
+	}
+	std::cout << std::endl;
+}
+
+void CBitVector::Transpose(std::size_t rows, std::size_t columns) {
+#ifdef SIMPLE_TRANSPOSE
+	SimpleTranspose(rows, columns);
+#else
+	EklundhBitTranspose(rows, columns);
+#endif
+}
+
+void CBitVector::SimpleTranspose(std::size_t rows, std::size_t columns) {
+	CBitVector temp(rows * columns);
+	temp.Copy(m_pBits, 0, rows * columns / 8);
+	for (std::size_t i = 0; i < rows; i++) {
+		for (std::size_t j = 0; j < columns; j++) {
+			SetBit(j * rows + i, temp.GetBit(i * columns + j));
+		}
+	}
+}
+
+//A transposition algorithm for bit-matrices of size 2^i x 2^i
+void CBitVector::EklundhBitTranspose(std::size_t rows, std::size_t columns) {
+	REGISTER_SIZE* rowaptr;	//ptr;
+	REGISTER_SIZE* rowbptr;
+	REGISTER_SIZE temp_row;
+	REGISTER_SIZE mask;
+	REGISTER_SIZE invmask;
+	REGISTER_SIZE* lim;
+
+	lim = (REGISTER_SIZE*) m_pBits + ceil_divide(rows * columns, 8);
+
+	std::size_t offset = (columns >> 3) / sizeof(REGISTER_SIZE);
+	std::size_t numiters = ceil_log2(std::min(rows, columns));
+	std::size_t srcidx = 1, destidx;
+	std::size_t rounds;
+
+	//If swapping is performed on bit-level
+	for (std::size_t i = 0; i < LOG2_REGISTER_SIZE; i++, srcidx *= 2) {
+		destidx = offset * srcidx;
+		rowaptr = (REGISTER_SIZE*) m_pBits;
+		rowbptr = rowaptr + destidx;
+
+		//Preset the masks that are required for bit-level swapping operations
+		mask = TRANSPOSITION_MASKS[i];
+		invmask = ~mask;
+
+		//If swapping is performed on byte-level reverse operations due to little-endian format.
+		rounds = rows / (srcidx * 2);
+		if (i > 2) {
+			for (std::size_t j = 0; j < rounds; j++) {
+				for (lim = rowbptr + destidx; rowbptr < lim; rowaptr++, rowbptr++) {
+					temp_row = *rowaptr;
+					*rowaptr = ((*rowaptr & mask) ^ ((*rowbptr & mask) << srcidx));
+					*rowbptr = ((*rowbptr & invmask) ^ ((temp_row & invmask) >> srcidx));
+				}
+				rowaptr += destidx;
+				rowbptr += destidx;
+			}
+		} else {
+			for (std::size_t j = 0; j < rounds; j++) {
+				for (lim = rowbptr + destidx; rowbptr < lim; rowaptr++, rowbptr++) {
+					temp_row = *rowaptr;
+					*rowaptr = ((*rowaptr & invmask) ^ ((*rowbptr & invmask) >> srcidx));
+					*rowbptr = ((*rowbptr & mask) ^ ((temp_row & mask) << srcidx));
+				}
+				rowaptr += destidx;
+				rowbptr += destidx;
+			}
+		}
+	}
+
+	for (std::size_t i = LOG2_REGISTER_SIZE, swapoffset = 1, dswapoffset; i < numiters; i++, srcidx *= 2, swapoffset = swapoffset << 1) {
+		destidx = offset * srcidx;
+		dswapoffset = swapoffset << 1;
+		rowaptr = (REGISTER_SIZE*) m_pBits;
+		rowbptr = rowaptr + destidx - swapoffset;
+
+		rounds = rows / (srcidx * 2);
+		for (std::size_t j = 0; j < rows / (srcidx * 2); j++) {
+			std::size_t p;
+			for (p = 0, lim = rowbptr + destidx; p < destidx && rowbptr < lim; p++, rowaptr++, rowbptr++) {
+				if ((p % dswapoffset >= swapoffset)) {
+					temp_row = *rowaptr;
+					*rowaptr = *rowbptr;
+					*rowbptr = temp_row;
+				}
+			}
+			rowaptr += destidx;
+			rowbptr += destidx;
+		}
+	}
+
+	if (columns > rows) {
+		BYTE* tempvec = (BYTE*) malloc((rows * columns) / 8);
+		memcpy(tempvec, m_pBits, ((rows / 8) * columns));
+
+		rowaptr = (REGISTER_SIZE*) m_pBits;
+		std::size_t rowbytesize = rows / 8;
+		std::size_t rowregsize = rows / (sizeof(REGISTER_SIZE) * 8);
+		for (std::size_t i = 0; i < columns / rows; i++) {
+			rowbptr = (REGISTER_SIZE*) tempvec;
+			rowbptr += (i * rowregsize);
+			for (std::size_t j = 0; j < rows; j++, rowaptr += rowregsize, rowbptr += offset) {
+				memcpy(rowaptr, rowbptr, rowbytesize);
+			}
+		}
+		free(tempvec);
+	}
+
+	if (rows > columns) {
+		BYTE* tempvec = (BYTE*) malloc((rows * columns) / 8);
+		memcpy(tempvec, m_pBits, ((rows / 8) * columns));
+
+		REGISTER_SIZE* rowaptr = (REGISTER_SIZE*) m_pBits;
+		std::size_t colbytesize = columns / 8;
+		std::size_t colregsize = columns / (sizeof(REGISTER_SIZE) * 8);
+		std::size_t offset_cols = (columns * columns) / (sizeof(REGISTER_SIZE) * 8);
+
+		for (std::size_t i = 0; i < columns; i++) {
+			rowbptr = (REGISTER_SIZE*) tempvec;
+			rowbptr += (i * colregsize);
+			for (std::size_t j = 0; j < rows / columns; j++, rowaptr += colregsize, rowbptr += offset_cols) {
+				memcpy(rowaptr, rowbptr, colbytesize);
+			}
+		}
+		free(tempvec);
+	}
+}

+ 717 - 0
2p-preprocessing/ENCRYPTO_utils/cbitvector.h

@@ -0,0 +1,717 @@
+/**
+ \file 		cbitvector.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		CBitVector Implementation
+ */
+
+#ifndef CBITVECTOR_H_
+#define CBITVECTOR_H_
+
+#include "typedefs.h"
+#include <cassert>
+#include <cstddef>
+
+// forward declarations
+class crypto;
+
+/** Class which defines the functionality of storing C-based Bits in vector type format.*/
+class CBitVector {
+public:
+
+	//Constructor code begins here...
+
+	/** Constructor which initializes the member variables bit pointer and size to NULL and zero respectively. */
+	CBitVector();
+
+	/**
+	 	 Overloaded constructor of class \link CBitVector \endlink which calls internally \link Create(std::size_t bits) \endlink
+	 	 \param  bits	 - It is the number of bits which will be used to allocate the CBitVector with. For more info on how these bits are allocated refer to \link Create(std::size_t bits) \endlink
+	 */
+	CBitVector(std::size_t bits);
+
+	/**
+	 	Overloaded constructor of class \link CBitVector \endlink which calls internally \link Create(std::size_t bits,crypto* crypt) \endlink
+	 	\param  bits	 - It is the number of bits which will be used to allocate the CBitVector with. For more info on how these bits are allocated refer to \link Create(std::size_t bits,crypto* crypt) \endlink
+	 	\param  crypt 	 - This object from crypto class is used to generate pseudo random values for the cbitvector.
+	 */
+	CBitVector(std::size_t bits, crypto* crypt);
+
+	//Constructor code ends here...
+
+	//Basic Primitive function of allocation and deallocation begins here.
+	/**
+	 	 Function which gets called initially when the cbitvector object is created. This method is mostly called from constructor of CBitVector class.
+	 	 The method sets bit pointer and size to NULL and zero respectively.
+	*/
+	void Init();
+
+	/**
+			Destructor which internally calls the delCBitVector for deallocating the space. This method internally calls
+			\link delCBitVector() \endlink.
+	*/
+	~CBitVector();
+
+	/**
+		This method is used to deallocate the bit pointer and size explicitly. This method needs to be called by the programmer explicitly.
+	*/
+	void delCBitVector();
+	//Basic Primitive function of allocation and deallocation ends here.
+
+
+	//Create function supported by CBitVector starts here...
+	/**
+		This method generates random values and assigns it to the bitvector using crypto object. If the bits provided in the params are greater
+		than the bit size of the bitvector, then the bit vector is recreated with new bit size and filled in with random values.
+
+		\param  bits	 - It is the number of bits which will be used to allocate and assign random values of the CBitVector with. For more info on how these bits are allocated refer to \link Create(std::size_t bits) \endlink
+		\param	crypt	 - It is the crypto class object which is used to generate random values for the bit size.
+	*/
+	void FillRand(std::size_t bits, crypto* crypt);
+
+
+
+	/* Create in bits and bytes */
+	
+	/**
+		This method is used to create the CBitVector with the provided bits. The method creates a bit vector of exactly ceil_divide(bits) size.
+		For example, if bit size provided is 3 after this method is called it will be 8 bits = 1 byte.
+
+		\param  bits	 - It is the number of bits which will be used to allocate the CBitVector with.
+	*/
+	void CreateExact(std::size_t bits);
+
+	/**
+		This method is used to create the CBitVector with the provided bits. The method creates a bit vector with a size close to AES Bitsize.
+		For example, if bit size provided is 110. After this method is called it will be 128 bits. It will perform a ceil of provided_bit_size
+		to AES bit size and multiply that ceiled value with AES bits size. (For reference, AES Bit size is taken as 128 bits)
+
+		\param  bits	 - It is the number of bits which will be used to allocate the CBitVector with.
+	*/
+	void Create(std::size_t bits);
+
+
+	/**
+		This method is used to create the CBitVector with the provided byte size. The method creates a bit vector with a size close to AES Bytesize.
+		For example, if byte size provided is 9. After this method is called it will be 16 bytes. It will perform a ceil of provided_byte_size
+		to AES byte size and multiply that ceiled value with AES byte size. (For reference, AES Byte size is taken as 16 bytes). Internally, this method
+		calls \link Create(std::size_t bits) \endlink. Therefore, for further info please refer to the internal method provided.
+
+		\param  bytes	 - It is the number of bytes which will be used to allocate the CBitVector with.
+	*/
+	void CreateBytes(std::size_t bytes);
+
+	/**
+		This method is used to create the CBitVector with the provided byte size and fills it with random data from the crypt object. The method creates a
+		bit vector with a size close to AES Bytesize. For example, if byte size provided is 9. After this method is called it will be 16 bytes. It will perform a ceil of provided_byte_size
+		to AES byte size and multiply that ceiled value with AES byte size. (For reference, AES Byte size is taken as 16 bytes). Internally, this method
+		calls \link Create(std::size_t bits, crypto* crypt) \endlink. Therefore, for further info please refer to the internal method provided.
+
+		\param  bytes	 - It is the number of bytes which will be used to allocate the CBitVector with.
+		\param  crypt	 - Reference to a crypto object from which fresh randomness is sampled
+	*/
+	void CreateBytes(std::size_t bytes, crypto* crypt);
+
+	/**
+		This method is used to create the CBitVector with the provided bits and set them to value zero. The method creates a bit vector with a size close to AES Bitsize.
+		And performs an assignment of zero to each bit being allocated. Internally, this method calls \link Create(std::size_t bits) \endlink. Therefore, for further info
+		please refer to the internal method provided.
+
+		\param  bits	 - It is the number of bits which will be used to allocate and assign zero values of the CBitVector with.
+	*/
+	void CreateZeros(std::size_t bits);
+
+	/**
+		This method is used to create the CBitVector with the provided bits and set them to some random values. The method creates a bit vector with a size close to AES Bitsize.
+		And performs an assignment of random values to each bit being allocated. Internally, this method calls \link Create(std::size_t bits) \endlink and
+		\link FillRand(std::size_t bits, crypto* crypt) \endlink. Therefore, for further info please refer to the internal method provided.
+
+		\param  bits	 - It is the number of bits which will be used to allocate and assign random values of the CBitVector with.
+		\param	crypt	 - It is the crypto class object which is used to generate random values for the bit size.
+	*/
+	void Create(std::size_t bits, crypto* crypt);
+
+
+	/**
+		This method is used create the CBitVector with the provided number of elements and element length. This method basically creates a 1-dimensional array/vector with the provided
+		element size and number of elements. This method internally calls \link Create(std::size_t bits) \endlink with arguments as elementlength*numelements.
+		\param numelements		- The number of elements in the 1-dimensional array/vector which gets created.
+		\param elementlength	- The size of element in the provided cbitvector.
+	*/
+	void Create(std::size_t numelements, std::size_t elementlength);
+
+	/**
+		This method is used create the CBitVector with the provided number of elements and element length and then assign random values to them. This method basically creates
+		a 1-dimensional array/vector with the provided element size and number of elements and assign some random values based on crypt object provided. This method internally
+		calls \link Create(std::size_t bits, crypto* crypt) \endlink for creation of 1-d vector.
+		\param numelements		- The number of elements in the 1-dimensional array/vector which gets created.
+		\param elementlength	- The size of element in the provided cbitvector.
+		\param crypt			- It is the crypto class object which is used to generate random values for the provided bit size.
+	*/
+	void Create(std::size_t numelements, std::size_t elementlength, crypto* crypt);
+
+	/**
+		This method is used create the CBitVector with the provided number of elements of 2 dimensions and element length. This method basically creates a 2-dimensional array/vector
+		with the provided element size and number of elements in two dimensions. This method internally calls \link Create(std::size_t bits) \endlink with arguments as
+		elementlength*numelementsDimA*numelementsDimB.
+		\param numelementsDimA		- The number of elements in the 1st-dimension of the 2d array/vector which gets created.
+		\param numelementsDimB		- The number of elements in the 2nd-dimension of the 2d array/vector which gets created.
+		\param elementlength		- The size of element in the provided cbitvector.
+	*/
+	void Create(std::size_t numelementsDimA, std::size_t numelementsDimB, std::size_t elementlength);
+	/**
+		This method is used create the CBitVector with the provided number of elements of 2 dimensions and element length, and then assign random values to them. This method basically
+		creates a 2-dimensional array/vector with the provided element size and number of elements in two dimensions  and assign some random values based on crypt object provided.
+		This method internally calls \link Create(std::size_t bits, crypto* crypt) \endlink.
+		\param numelementsDimA		- The number of elements in the 1st-dimension of the 2d array/vector which gets created.
+		\param numelementsDimB		- The number of elements in the 2nd-dimension of the 2d array/vector which gets created.
+		\param elementlength		- The size of element in the provided cbitvector.
+		\param crypt				- It is the crypto class object which is used to generate random values for the provided bit size.
+	*/
+	void Create(std::size_t numelementsDimA, std::size_t numelementsDimB, std::size_t elementlength, crypto* crypt);
+	//Create function supported by CBitVector ends here...
+
+
+
+	/*
+	 * Management operations
+	 */
+
+	/**
+		This method is used to resize the bytes allocated to CBitVector with newly provided size. And also accommodate the data from previous allocation to new one.
+		\param newSizeBytes		-	This variable provides the new size to which the cbitvector needs to be modified to user's needs.
+	*/
+	void ResizeinBytes(std::size_t newSizeBytes);
+
+	/**
+		This method is used to reset the values in the given CBitVector. This method sets all bit values to zeros. This is a slight variant of the method
+		\link CreateZeros(std::size_t bits) \endlink. The create method mentioned above allocates and sets value to zero. Whereas the provided method only
+		sets the value to zero.
+	*/
+	void Reset();
+
+	/**
+		This method is used to reset the values in the given CBitVector for specific byte range.
+		\param 	frombyte	-	The source byte position from which the values needs to be reset.
+		\param 	tobyte		-	The destination byte position until which the values needs to be reset to.
+	*/
+	void ResetFromTo(std::size_t frombyte, std::size_t tobyte);
+
+	/**
+		This method sets all bit position values in a CBitVector to One.
+	*/
+	void SetToOne();
+
+	/**
+		This method sets all bits in the CBitVector to the inverse
+	*/
+	void Invert();
+
+
+	/**
+		This is a getter method which returns the size of the CBitVector in bytes.
+		\return the byte size of CBitVector.
+	*/
+	std::size_t GetSize() const;
+
+	/**
+		This method checks if two CBitVectors are equal or not.
+		\param	vec		-		Vector to be checked with current one for the case of equality.
+		\return	boolean value which says whether it is equal or not.
+	*/
+	BOOL IsEqual(const CBitVector& vec) const;
+
+	/**
+		This method checks if two CBitVectors are equal or not for a given range of bit positions.
+		\param	vec		-		Vector to be checked with current one for the case of equality.
+		\param  from	-		Bit Position from which the vectors need to be checked for equality.
+		\param	to	 	-		Bit Position until which the vectors need to be checked for equality.
+		\return	boolean value which says whether the vectors are equal or not in the provided range of bits.
+	*/
+	BOOL IsEqual(const CBitVector& vec, std::size_t from, std::size_t to) const;
+
+	/**
+		This method sets the element length of the CBitVector. It can be used to modify the object size in a CBitVector when
+		around with the multi dimensional arrays/vectors.
+		\param	elelen	-		New element length which can be used to set the object size in a CBitVector.
+	*/
+	void SetElementLength(std::size_t elelen);
+
+
+	/**
+		This method gets the element length of the CBitVector.
+		\return element length of the elements in CBitVector.
+	*/
+	std::size_t GetElementLength() const;
+
+	/*
+	 * Copy operations
+	 */
+
+	/**
+		This method is used to copy the provided CBitVector to itself. It internally calls
+		\link Copy(BYTE* p, int pos, int len) \endlink for copying bytewise.
+		\param	vec		- 		The vector from which the copying needs to be performed.
+	*/
+	void Copy(const CBitVector& vec);
+
+	/**
+		This method is used to copy the provided CBitVector to itself for a given range. It internally calls \link Copy(BYTE* p, int pos, int len) \endlink
+		for copying bytewise. Copying is done in a slightly different way. Here the range is pos and len. The offset is defined for the base vector and not
+		for the copying vector. So if the method is called as B.Copy(A,5,10) then, values of vector A will be copied from first index location for length 10
+		to the vector B from position 5 for length 10. Unlike copying values from 5 position in vector A to vector B for length 10.
+		\param	vec		- 		The vector from which the copying needs to be performed.
+		\param	pos		- 		The positional offset for copying into current vector.
+		\param	len		-		Length or amount of values to be copied to the current vector from provided vector.
+	*/
+	void Copy(const CBitVector& vec, std::size_t pos, std::size_t len);
+
+	/**
+		This method is used to copy the current CBitVector with some ByteLocation with positional shift and length. This method is the base method for methods
+		\link Copy(CBitVector& vec, int pos, int len) \endlink and \link Copy(CBitVector& vec) \endlink.
+		\param	p		-		Pointer to the byte location to be copied to the CBitVector.
+		\param	pos		-		Positional offset for copying into current CBitVector.
+		\param	len		-  		Length or amount of values to be copied to the current vector from provided byte location.
+	*/
+	void Copy(const BYTE* p, std::size_t pos, std::size_t len);
+
+	/**
+		This method performs OR operation bytewise with the current CBitVector at the provided byte position with another Byte object.
+		\param	pos		- 		Byte position in the CBitVector which is used to perform OR operation with.
+		\param	p		-		Byte with which the OR operation is performed to get the result.
+
+	*/
+	void ORByte(std::size_t pos, BYTE p);
+
+	/*
+	 * Bitwise operations
+	 */
+
+	/**
+		This method gets the bit in the provided index by using the maskbits. The maskbits brings the concept of
+		endianness in the vector. In this method MASK_BIT is used to  extract the bits which are assumed to be
+		organized in Little Endian form.
+		\param	idx		-		Bit Index which needs to be fetched from the CBitVector.
+		\return The byte which has got just the bit in it.
+	*/
+	BYTE GetBit(std::size_t idx) const;
+
+	/**
+		This method sets the bit in the provided index by using the maskbits and the provided bit. The maskbits brings the concept of
+		endianness in the vector. In this method C_MASK_BIT is used to figure out the bits which are assumed to be
+		organized in Little Endian form.
+		\param	idx		-		Bit Index which needs to be written to in the CBitVector.
+		\param	b		-		The bit which being written in the provided index.
+	*/
+	void SetBit(std::size_t idx, BYTE b);
+
+	/**
+		This method gets the bit in the provided index without using the maskbits. The maskbits brings the concept of
+		endianness in the vector. In this method mask bits are not used so the vector is treated in Big Endian form.
+		\param	idx		-		Bit Index which needs to be fetched from the CBitVector.
+		\return The byte which has got just the bit in it.
+	*/
+	BYTE GetBitNoMask(std::size_t idx) const;
+
+	/**
+		This method sets the bit in the provided index without using the maskbits. The maskbits brings the concept of
+		endianness in the vector. In this method mask bits are not used so the vector is treated in Big Endian form.
+		\param	idx		-		Bit Index which needs to be written to in the CBitVector.
+		\param	b		-		The bit which being written in the provided index.
+	*/
+	void SetBitNoMask(std::size_t idx, BYTE b);
+
+	/**
+		This method XORs the bit in the provided index without using the maskbits. The maskbits brings the concept of
+		endianness in the vector. In this method mask bits are not used so the vector is treated in Big Endian form.
+		\param	idx		-		Bit Index which needs to be XORed to in the CBitVector.
+		\param	b		-		The bit which being XORed in the provided index.
+	*/
+	void XORBitNoMask(std::size_t idx, BYTE b);
+
+	/*
+	 * Single byte operations
+	 */
+
+	/**
+		This method sets a byte in a given index of the CBitVector with the provided Byte.
+		\param	idx		-	Index where the byte needs to be set.
+		\param	p		-	Byte which needs to be copied to.
+	*/
+	void SetByte(std::size_t idx, BYTE p);
+
+	/**
+		This method returns the byte at the given index in the CBitVector. Here the index is w.r.t bytes.
+		\param	idx		-	Index of the byte which needs to be returned from the CBitVector.
+		\return Byte is returned from CBitVector at the given index.
+	*/
+	BYTE GetByte(std::size_t idx) const;
+
+	/**
+		Not Used Currently in Framework.
+		This method performs XOR operation at the given index in the CBitVector with a provided Byte.
+		\param	idx		-	Index of the byte which needs to be XORed inside the CBitVector.
+		\param	b		- 	Byte to be XORed with the CBitVector.
+	*/
+	void XORByte(std::size_t idx, BYTE b);
+
+	/**
+		This method performs AND operation at the given index in the CBitVector with a provided Byte.
+		\param	idx		-	Index of the byte which needs to be ANDed inside the CBitVector.
+		\param	b		- 	Byte to be ANDed with the CBitVector.
+	*/
+	void ANDByte(std::size_t idx, BYTE b);
+
+	/*
+	 * Get Operations
+	 */
+
+	/**
+		This method gets elements from the CBitVector bitwise from a given offset for a given length. And stores the result
+		in the provided byte pointer. This method is used by the generic method \link Get(int pos, int len) \endlink
+		\param	p		-	The resulting bits for the given range in the CBitVector is stored in the byte pointer p.
+		\param	pos		-	The positional offset in the CBitVector from which the data needs to obtained.
+		\param	len		- 	The range limit of obtaining the data from the CBitVector.
+	*/
+	void GetBits(BYTE* p, std::size_t pos, std::size_t len) const;
+
+	/**
+		This method gets elements from the CBitVector bytewise from a given offset for a given length. And stores the result
+		in the provided byte pointer.
+		\param	p		-	The resulting bits for the given range in the CBitVector is stored in the byte pointer p.
+		\param	pos		-	The positional offset in the CBitVector from which the data needs to obtained.
+		\param	len		- 	The range limit of obtaining the data from the CBitVector.
+	*/
+	void GetBytes(BYTE* p, std::size_t pos, std::size_t len) const;
+
+	/**
+		Generic method which performs the operation of getting values from a CBitVector for a given bit position and length.
+		This method internally calls \link GetBits(BYTE* p, int pos, int len) \endlink.
+		\param	pos		-	The positional offset in the CBitVector from which the data needs to obtained.
+		\param	len		- 	The range limit of obtaining the data from the CBitVector.
+		\return	returns the value/values for the provided range.
+	*/
+	template<class T> T Get(std::size_t pos, std::size_t len) const {
+		assert(len <= sizeof(T) * 8);
+		T val = 0;
+		GetBits((BYTE*) &val, pos, len);
+		return val;
+	}
+
+	/*
+	 * Set Operations
+	 */
+	/**
+		The method for setting CBitVector for a given bit range with offset and length in unsigned 64bit integer format. This method
+		is called from \link SetBits(BYTE* p, int pos, int len) \endlink and \link Set(T val, int pos, int len) \endlink.
+		\param	p		-	Byte array passed to be set to the current CBitVector.
+		\param	pos		-	Positional offset in the CBitVector, where data will be set from the provided byte array.
+		\param	len		-   The range limit of obtaining the data from the CBitVector.
+	*/
+	void SetBits(const BYTE* p, std::size_t pos, std::size_t len);
+
+	/**
+		The method for setting CBitVector for a given bit range with offsets and length with another Byte Array.
+		\param	p		-	Byte array passed to be set with the current CBitVector.
+		\param	ppos	-	Positional offset in the Byte Array.
+		\param	pos		-	Positional offset in the CBitVector, where data will be set from the provided byte array.
+		\param	len		-	The range limit of obtaining the data from the CBitVector.
+	 */
+	void SetBitsPosOffset(const BYTE* p, std::size_t ppos, std::size_t pos, std::size_t len);
+
+	/**
+		The method for setting CBitVector for a given byte range with offset and length. This method internally calls the method
+		\link SetBytes(T* dst, T* src, T* lim) \endlink.
+		\param	src		-	Byte array passed to be set to the current CBitVector.
+		\param	pos		-	Byte position offset in the CBitVector, where data will be set from the provided byte array.
+		\param	len		-   The number of bytes to be set.
+	*/
+	void SetBytes(const BYTE* src, std::size_t pos, std::size_t len);
+
+	/**
+		This method sets the values in a given byte range to Zero in the current CBitVector.
+		\param	bytepos		-	Byte Positional offset in the CBitVector.
+		\param	bytelen		-	Byte Length in the CBitVector until which the value needs to be set to zero.
+	*/
+	void SetBytesToZero(std::size_t bytepos, std::size_t bytelen);
+
+	/**
+		Generic method which performs the operation of setting values to a CBitVector for a given bit position and length.
+		This method internally calls \link SetBits(BYTE* p, std::size_t pos, std::size_t len) \endlink.
+		\param	pos		-	The positional offset in the CBitVector from which the data needs to obtained.
+		\param	len		- 	The range limit of obtaining the data from the CBitVector.
+	*/
+	template<class T> void Set(T val, std::size_t pos, std::size_t len) {
+		assert(len <= sizeof(T) * 8);
+		SetBits((BYTE*) &val, pos, len);
+	}
+
+	/**
+		This method sets the values in a given bit range to Zero in the current CBitVector.
+		\param	bitpos		-	Bit Positional offset in the CBitVector.
+		\param	bitlen		-	Bit Length in the CBitVector until which the value needs to be set to zero.
+	*/
+	void SetBitsToZero(std::size_t bitpos, std::size_t bitlen);
+
+	/*
+	 * XOR Operations
+	 */
+
+	/**
+		This method performs XOR operation from a given position in the CBitVector with a provided Byte Array with a length.
+		This method is called from \link XORBytes(BYTE* p, int len) \endlink. This method internally calls \link XORBytes(T* dst, T* src, T* lim) \endlink.
+		\param	p		- 		Byte Array to be XORed with the CBitVector range.
+		\param	pos		-		Positional offset for XORing into current CBitVector.
+		\param	len		-  		Length or amount of values to be XORed to the current vector from provided byte location.
+	*/
+	void XORBytes(const BYTE* p, std::size_t pos, std::size_t len);
+	/**
+		This method performs XOR operation for a given length in the CBitVector with a provided Byte Array.	This method internally calls
+		\link XORBytes(BYTE* p, int pos, int len) \endlink.
+		\param	p		- 		Byte Array to be XORed with the CBitVector range.
+		\param	len		-  		Length or amount of values to be XORed to the current vector from provided byte location.
+	*/
+	void XORBytes(const BYTE* p, std::size_t len);
+
+	/**
+	 	Not Used in the Framework.
+		This method performs XOR operation from a given position in the CBitVector with another CBitVector with a length.
+		This method internally calls \link XORBytes(BYTE* p, int pos, int len) \endlink.
+		\param	vec		- 		Provided Array to be XORed with the CBitVector.
+		\param	pos		-		Positional offset for XORing into current CBitVector.
+		\param	len		-  		Length or amount of values to be XORed to the current vector from provided byte location.
+	*/
+	void XORVector(const CBitVector &vec, std::size_t pos, std::size_t len);
+
+	/**
+		Generic method which is used to XOR bit wise the CBitVector. This method internally calls
+		\link XORBits(BYTE* p, int pos, int len) \endlink.
+	*/
+	template<class T> void XOR(T val, std::size_t pos, std::size_t len) {
+		assert(len <= sizeof(T) * 8);
+		XORBits((BYTE*) &val, pos, len);
+	}
+
+	/**
+		The method for XORing CBitVector for a given bit range with offset and length. This method is called from
+		\link XOR(T val, int pos, int len) \endlink.
+		\param	p		-	Byte array passed to be XORed with the current CBitVector.
+		\param	pos		-	Positional offset in the CBitVector, where data will be XORed from the provided byte array.
+		\param	len		-   The range limit of obtaining the data from the CBitVector.
+	*/
+	void XORBits(const BYTE* p, std::size_t pos, std::size_t len);
+
+	/**
+		The method for XORing CBitVector for a given bit range with offsets and length with another Byte Array.
+		\param	p		-	Byte array passed to be XORed with the current CBitVector.
+		\param	ppos	-	Positional offset in the Byte Array.
+		\param	pos		-	Positional offset in the CBitVector, where data will be XORed from the provided byte array.
+		\param	len		-   The range limit of obtaining the data from the CBitVector.
+	*/
+	void XORBitsPosOffset(const BYTE* p, std::size_t ppos, std::size_t pos, std::size_t len);
+
+	/**
+		Set the value of this CBitVector to this XOR b
+		\param	b		-	Pointer to a CBitVector which is XORed on this CBitVector
+	*/
+	void XOR(const CBitVector* b);
+
+	/**
+		This method performs XOR operation from a given position in the CBitVector with a provided Byte Array with a length.
+		The XORing is performed in a slightly different way. The byte array is reversed before it is XORed with the CBitVector.
+		This method is called from \link XORBytes(BYTE* p, int len) \endlink. This method internally calls \link XORBytes(T* dst, T* src, T* lim) \endlink.
+		\param	p		- 		Byte Array to be XORed with the CBitVector range.
+		\param	pos		-		Positional offset for XORing into current CBitVector.
+		\param	len		-  		Length or amount of values to be XORed to the current vector from provided byte location.
+	*/
+	void XORBytesReverse(const BYTE* p, std::size_t pos, std::size_t len);
+
+	/*
+	 * AND Operations
+	 */
+
+	/**
+		This method performs AND operation from a given position in the CBitVector with a provided Byte Array with a length.
+		This method internally calls \link ANDBytes(T* dst, T* src, T* lim) \endlink.
+		\param	p		- 		Byte Array to be ANDed with the CBitVector range.
+		\param	pos		-		Positional offset for ANDing into current CBitVector.
+		\param	len		-  		Length or amount of values to be ANDed to the current vector from provided byte location.
+	*/
+	void ANDBytes(const BYTE* p, std::size_t pos, std::size_t len);
+
+	/*
+	 * Set operations
+	 */
+	/**
+		This method is used to set and XOR a CBitVector with a byte array and then XOR it with another byte array
+		for a given range. This method internally calls \link Copy(BYTE* p, int pos, int len) \endlink and
+		\link XORBytes(BYTE* p, int pos, int len) \endlink.
+		\param	p		-		Pointer to the byte location to be copied to the CBitVector.
+		\param 	q		-		Pointer to the byte location with which the CBitVector is XORed with.
+		\param	pos		-		Positional offset for copying and XORing into current CBitVector.
+		\param	len		-  		Length or amount of values to be copied and XORed to the current vector from provided byte location.
+	*/
+	void SetXOR(const BYTE* p, const BYTE* q, std::size_t pos, std::size_t len);
+
+	/**
+		This method is used to set and AND a CBitVector with a byte array and then AND it with another byte array
+		for a given range. This method internally calls \link Copy(BYTE* p, int pos, int len) \endlink and
+		\link ANDBytes(BYTE* p, int pos, int len) \endlink.
+		\param	p		-		Pointer to the byte location to be copied to the CBitVector.
+		\param 	q		-		Pointer to the byte location with which the CBitVector is ANDed with.
+		\param	pos		-		Positional offset for copying and ANDing into current CBitVector.
+		\param	len		-  		Length or amount of values to be copied and ANDed to the current vector from provided byte location.
+	*/
+	void SetAND(const BYTE* p, const BYTE* q, std::size_t pos, std::size_t len);
+
+	/**
+		Set the value of this CBitVector to this AND b
+		\param	b		-	Pointer to a CBitVector which is ANDed on this CBitVector
+	*/
+	void AND(const CBitVector* b);
+
+	/**
+		Cyclic shift left by pos positions
+		\param	pos		-	the left shift value
+	*/
+	void CLShift(std::size_t pos);
+
+
+	/*
+	 * Buffer access operations
+	 */
+
+	/**
+		This method returns CBitVector in byte array format. This is very widely used method.
+	*/
+	BYTE* GetArr();
+	const BYTE* GetArr() const;
+
+	/**
+		This method is used to attach a new buffer into the CBitVector provided as arguments to this method.
+		\param	p		-		Pointer to the byte location to be attached to the CBitVector.
+		\param  size	-		Number of bytes attached from the provided buffer.
+	*/
+	void AttachBuf(BYTE* p, std::size_t size = 0);
+
+	/**
+		This method is used to detach the buffer from the CBitVector. */
+	void DetachBuf();
+
+	/*
+	 * Print Operations
+	 */
+
+	/**
+		This method prints the CBitVector bitwise for provided bit range. This method internally calls \link  GetBitNoMask(int idx) \endlink.
+		This method is called from \link PrintBinary() \endlink.
+		\param	fromBit			-		The bit from which the printing starts in a CBitVector.
+		\param	toBit			-		The bit until which the printing in a CBitVector is done.
+	*/
+	void Print(std::size_t fromBit, std::size_t toBit);
+
+	/**
+		This method prints the CBitVector in Hexadecimal format.
+	*/
+	void PrintHex(bool linebreak = true);
+
+	/**
+		This method prints the CBitVector in Hexadecimal format for the provided byte range.
+		\param	fromByte		-		The byte from which the printing of CBitVector begins.
+		\param	toByte			-		The byte until which the printing of CBitVector is done.
+	*/
+	void PrintHex(std::size_t fromByte, std::size_t toByte, bool linebreak = true);
+
+	/**
+		This method prints the CBitVector in Binary format. This method internally calls \link Print(int fromBit, int toBit) \endlink.
+	*/
+	void PrintBinary();
+
+	/**
+		This method is a more abstract printing method which is used to print the CBitVector even if the vector is a simple 1 bit based
+		vector or 1-d array/vector or even a 2-d vector/array. This method internally calls methods \link Get(int i) \endlink and
+		\link Get2D(int i, int j) \endlink.
+	*/
+	void PrintContent();
+
+	/**
+		This method prints the CBitVector bitwise for provided bit range with mask. This method internally calls \link  GetBit(int idx) \endlink.
+		\param	fromBit			-		The bit from which the printing starts in a CBitVector.
+		\param	toBit			-		The bit until which the printing in a CBitVector is done.
+	*/
+	void PrintBinaryMasked(std::size_t from, std::size_t to);
+
+	/*
+	 * If the cbitvector is abstracted to an array of elements with m_nElementLength bits size, these methods can be used for easier access
+	 */
+
+	/**
+		Generic method which provides more abstraction for getting elements in the CBitVector. It is mainly used for getting values which are
+		1-dimensional in nature. This method internally calls \link Get(int pos, int len) \endlink.
+		\param	i		-		Index from which data needs to be fetched.
+	*/
+	template<class T> T Get(std::size_t i) const {
+		return Get<T>(i * m_nElementLength, m_nElementLength);
+	}
+	/**
+		Generic method which provides more abstraction for setting elements in the CBitVector. It is mainly used for getting values which are
+		1-dimensional in nature. This method internally calls \link Set(int pos, int len) \endlink.
+		\param	val		-		Value which needs to be written to the given location.
+		\param	i		-		Index to which data needs to be written to.
+	*/
+	template<class T> void Set(T val, std::size_t i) {
+		Set<T>(val, i * m_nElementLength, m_nElementLength);
+	}
+	/*
+	 * The same as the above methods only for two-dimensional access
+	 */
+	/**
+		Generic method which provides more abstraction for getting elements in the CBitVector. It is mainly used for getting values which are
+		2-dimensional in nature. This method internally calls \link Get(int pos, int len) \endlink.
+		\param	i		-		Row index from which the data needs to be read.
+		\param	j		-		Column index from which the data needs to be read.
+	*/
+	template<class T> T Get2D(std::size_t i, std::size_t j) const {
+		return Get<T>((i * m_nNumElementsDimB + j) * m_nElementLength, m_nElementLength);
+	}
+
+	/**
+		Generic method which provides more abstraction for setting elements in the CBitVector. It is mainly used for getting values which are
+		2-dimensional in nature. This method internally calls \link Set(int pos, int len) \endlink.
+		\param	val		-		Value which needs to be written to the given location.
+		\param	i		-		Row index from which the data needs to be written.
+		\param	j		-		Column index from which the data needs to be written.
+	*/
+	template<class T> void Set2D(T val, std::size_t i, std::size_t j) {
+		Set<T>(val, (i * m_nNumElementsDimB + j) * m_nElementLength, m_nElementLength);
+	}
+	//useful when accessing elements using an index
+
+	//View the cbitvector as a rows x columns matrix and transpose
+	void Transpose(std::size_t rows, std::size_t columns);
+	void SimpleTranspose(std::size_t rows, std::size_t columns);
+	void EklundhBitTranspose(std::size_t rows, std::size_t columns);
+
+//private:
+public:
+	BYTE* m_pBits;	/** Byte pointer which stores the CBitVector as simple byte array. */
+	std::size_t m_nByteSize; /** Byte size variable which stores the size of CBitVector in bytes. */
+	std::size_t m_nBits; //The exact number of bits
+	std::size_t m_nElementLength; /** Size of elements in the CBitVector. By default, it is set to 1. It is used
+	 	 	 	 	 	 	 	   differently when it is used as 1-d or 2-d custom vector/array. */
+	std::size_t m_nNumElements;  /** Number elements in the first dimension in the CBitVector. */
+	std::size_t m_nNumElementsDimB;/** Number elements in the second dimension in the CBitVector. */
+};
+
+#endif /* BITVECTOR_H_ */

+ 163 - 0
2p-preprocessing/ENCRYPTO_utils/channel.cpp

@@ -0,0 +1,163 @@
+/**
+ \file 		channel.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 Engineering Cryptographic Protocols Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "channel.h"
+
+#include "typedefs.h"
+#include "rcvthread.h"
+#include "sndthread.h"
+#include <cassert>
+#include <cstring>
+
+
+channel::channel(uint8_t channelid, RcvThread* rcver, SndThread* snder)
+	: m_bChannelID(channelid), m_cRcver(rcver), m_cSnder(snder),
+	m_eRcved(std::make_unique<CEvent>()), m_eFin(std::make_unique<CEvent>()),
+	m_bSndAlive(true), m_bRcvAlive(true),
+	m_qRcvedBlocks(rcver->add_listener(channelid, m_eRcved.get(), m_eFin.get())),
+	m_qRcvedBlocks_mutex_(rcver->get_listener_mutex(channelid))
+{
+	assert(rcver->getlock() == snder->getlock());
+}
+
+channel::~channel() {
+	if(m_bRcvAlive) {
+		m_cRcver->remove_listener(m_bChannelID);
+	}
+}
+
+void channel::send(uint8_t* buf, uint64_t nbytes) {
+	assert(m_bSndAlive);
+	m_cSnder->add_snd_task(m_bChannelID, nbytes, buf);
+}
+
+
+void channel::blocking_send(CEvent* eventcaller, uint8_t* buf, uint64_t nbytes) {
+	assert(m_bSndAlive);
+	m_cSnder->add_event_snd_task(eventcaller, m_bChannelID, nbytes, buf);
+	eventcaller->Wait();
+}
+
+void channel::send_id_len(uint8_t* buf, uint64_t nbytes, uint64_t id, uint64_t len) {
+	assert(m_bSndAlive);
+	m_cSnder->add_snd_task_start_len(m_bChannelID, nbytes, buf, id, len);
+}
+
+void channel::blocking_send_id_len(CEvent* eventcaller, uint8_t* buf, uint64_t nbytes, uint64_t id, uint64_t len) {
+	assert(m_bSndAlive);
+	m_cSnder->add_event_snd_task_start_len(eventcaller, m_bChannelID, nbytes, buf, id, len);
+	eventcaller->Wait();
+}
+
+//buf needs to be freed, data contains the payload
+uint8_t* channel::blocking_receive_id_len(uint8_t** data, uint64_t* id, uint64_t* len) {
+	uint8_t* buf = blocking_receive();
+	*data = buf;
+	*id = *((uint64_t*) *data);
+	(*data)  += sizeof(uint64_t);
+	*len = *((uint64_t*) *data);
+	(*data) += sizeof(uint64_t);
+
+	return buf;
+}
+
+bool channel::queue_empty() const {
+	std::lock_guard<std::mutex> lock(m_qRcvedBlocks_mutex_);
+	bool qempty = m_qRcvedBlocks->empty();
+	return qempty;
+}
+
+uint8_t* channel::blocking_receive() {
+	assert(m_bRcvAlive);
+	while(queue_empty())
+		m_eRcved->Wait();
+	rcv_ctx* ret = nullptr;
+	uint8_t* ret_block = nullptr;
+	{
+		std::lock_guard<std::mutex> lock(m_qRcvedBlocks_mutex_);
+		ret = (rcv_ctx*) m_qRcvedBlocks->front();
+		ret_block = ret->buf;
+		m_qRcvedBlocks->pop();
+	}
+	free(ret);
+
+	return ret_block;
+}
+
+void channel::blocking_receive(uint8_t* rcvbuf, uint64_t rcvsize) {
+	assert(m_bRcvAlive);
+	while(queue_empty())
+		m_eRcved->Wait();
+
+	std::unique_lock<std::mutex> lock(m_qRcvedBlocks_mutex_);
+	rcv_ctx* ret = (rcv_ctx*) m_qRcvedBlocks->front();
+	uint8_t* ret_block = ret->buf;
+	uint64_t rcved_this_call = ret->rcvbytes;
+	if(rcved_this_call == rcvsize) {
+		m_qRcvedBlocks->pop();
+		lock.unlock();
+		free(ret);
+	} else if(rcvsize < rcved_this_call) {
+		//if the block contains too much data, copy only the receive size
+		ret->rcvbytes -= rcvsize;
+		uint8_t* newbuf = (uint8_t*) malloc(ret->rcvbytes);
+		memcpy(newbuf, ret->buf+rcvsize, ret->rcvbytes);
+		ret->buf = newbuf;
+		lock.unlock();
+		rcved_this_call = rcvsize;
+	} else {
+		//I want to receive more data than are in that block. Perform recursive call (might become troublesome for too many recursion steps)
+		m_qRcvedBlocks->pop();
+		lock.unlock();
+		free(ret);
+		uint8_t* new_rcvbuf_start = rcvbuf + rcved_this_call;
+		uint64_t new_rcvsize = rcvsize -rcved_this_call;
+
+		blocking_receive(new_rcvbuf_start, new_rcvsize);
+	}
+	memcpy(rcvbuf, ret_block, rcved_this_call);
+	free(ret_block);
+}
+
+
+bool channel::is_alive() {
+	return (!(queue_empty() && m_eFin->IsSet()));
+}
+
+bool channel::data_available() {
+	return !queue_empty();
+}
+
+void channel::signal_end() {
+	m_cSnder->signal_end(m_bChannelID);
+	m_bSndAlive = false;
+}
+
+void channel::wait_for_fin() {
+	m_eFin->Wait();
+	m_bRcvAlive = false;
+}
+
+void channel::synchronize_end() {
+	if(m_bSndAlive)
+		signal_end();
+	if(m_bRcvAlive)
+		m_cRcver->flush_queue(m_bChannelID);
+	if(m_bRcvAlive)
+		wait_for_fin();
+
+}

+ 78 - 0
2p-preprocessing/ENCRYPTO_utils/channel.h

@@ -0,0 +1,78 @@
+/**
+ \file 		channel.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 Engineering Cryptographic Protocols Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHANNEL_H_
+#define CHANNEL_H_
+
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+class RcvThread;
+class SndThread;
+struct rcv_ctx;
+class CEvent;
+class CLock;
+
+class channel {
+public:
+	channel(uint8_t channelid, RcvThread* rcver, SndThread* snder);
+
+	~channel();
+
+	void send(uint8_t* buf, uint64_t nbytes);
+
+	void blocking_send(CEvent* eventcaller, uint8_t* buf, uint64_t nbytes);
+
+	void send_id_len(uint8_t* buf, uint64_t nbytes, uint64_t id, uint64_t len);
+
+	void blocking_send_id_len(CEvent* eventcaller, uint8_t* buf, uint64_t nbytes, uint64_t id, uint64_t len);
+
+	//buf needs to be freed, data contains the payload
+	uint8_t* blocking_receive_id_len(uint8_t** data, uint64_t* id, uint64_t* len);
+
+    bool queue_empty() const;
+
+	uint8_t* blocking_receive();
+
+	void blocking_receive(uint8_t* rcvbuf, uint64_t rcvsize);
+
+	bool is_alive();
+
+	bool data_available();
+
+	void signal_end();
+
+	void wait_for_fin();
+
+	void synchronize_end();
+
+private:
+	uint8_t m_bChannelID;
+	RcvThread* m_cRcver;
+	SndThread* m_cSnder;
+	std::unique_ptr<CEvent> m_eRcved;
+	std::unique_ptr<CEvent> m_eFin;
+	bool m_bSndAlive;
+	bool m_bRcvAlive;
+	std::queue<rcv_ctx*>* m_qRcvedBlocks;
+	std::mutex& m_qRcvedBlocks_mutex_;
+};
+
+
+#endif /* CHANNEL_H_ */

+ 53 - 0
2p-preprocessing/ENCRYPTO_utils/circular_queue.cpp

@@ -0,0 +1,53 @@
+/**
+ \file 		circular_queue.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Circular Queue Implementation
+ */
+
+#include "circular_queue.h"
+#include <cstdlib>
+
+CQueue::CQueue(int maxsize) {
+	head = 0;
+	tail = 0;
+
+	queuesize = maxsize;
+	queue = (int*) malloc(sizeof(int) * queuesize);
+}
+
+CQueue::~CQueue() {
+	if (queue)
+		free(queue);
+}
+
+void CQueue::enq(int ele) {
+	queue[head] = ele;
+	head = (head + 1) % queuesize;
+}
+
+int CQueue::deq() {
+	int ret = queue[tail];
+	tail = (tail + 1) % queuesize;
+	return ret;
+}
+
+int CQueue::size() {
+	int rem = (head - tail) % queuesize;
+	if (rem < 0)
+		return queuesize + rem;
+	else
+		return rem;
+}
+

+ 38 - 0
2p-preprocessing/ENCRYPTO_utils/circular_queue.h

@@ -0,0 +1,38 @@
+/**
+ \file 		circular_queue.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Circular Queue class Implementation
+ */
+
+#ifndef __CQUEUE__
+#define __CQUEUE__
+
+
+class CQueue {
+private:
+	int queuesize;
+	int head;
+	int tail;
+	int* queue;
+public:
+	CQueue(int maxsize);
+	~CQueue();
+	void enq(int ele);
+	int deq();
+	int size();
+
+};
+
+#endif

+ 302 - 0
2p-preprocessing/ENCRYPTO_utils/codewords.cpp

@@ -0,0 +1,302 @@
+/**
+ \file 		codewords.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		A hard-coded Welsh-Hadamard code for up to 8-bit words and resulting 256-bit codewords
+ */
+
+#include "codewords.h"
+
+const uint32_t CODE_MATRIX[m_nCodewords][m_nCWIntlen] = { \
+		{0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+		{0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa}, \
+		{0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc}, \
+		{0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666, 0x66666666}, \
+		{0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0}, \
+		{0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a}, \
+		{0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c}, \
+		{0x96969696, 0x96969696, 0x96969696, 0x96969696, 0x96969696, 0x96969696, 0x96969696, 0x96969696}, \
+		{0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00}, \
+		{0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa}, \
+		{0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc}, \
+		{0x99669966, 0x99669966, 0x99669966, 0x99669966, 0x99669966, 0x99669966, 0x99669966, 0x99669966}, \
+		{0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0}, \
+		{0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a}, \
+		{0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c}, \
+		{0x69966996, 0x69966996, 0x69966996, 0x69966996, 0x69966996, 0x69966996, 0x69966996, 0x69966996}, \
+		{0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000}, \
+		{0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa}, \
+		{0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc}, \
+		{0x99996666, 0x99996666, 0x99996666, 0x99996666, 0x99996666, 0x99996666, 0x99996666, 0x99996666}, \
+		{0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0}, \
+		{0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a}, \
+		{0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c}, \
+		{0x69699696, 0x69699696, 0x69699696, 0x69699696, 0x69699696, 0x69699696, 0x69699696, 0x69699696}, \
+		{0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00}, \
+		{0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa}, \
+		{0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc}, \
+		{0x66999966, 0x66999966, 0x66999966, 0x66999966, 0x66999966, 0x66999966, 0x66999966, 0x66999966}, \
+		{0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0}, \
+		{0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a}, \
+		{0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c}, \
+		{0x96696996, 0x96696996, 0x96696996, 0x96696996, 0x96696996, 0x96696996, 0x96696996, 0x96696996}, \
+		{0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, \
+		{0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa}, \
+		{0x33333333, 0xcccccccc, 0x33333333, 0xcccccccc, 0x33333333, 0xcccccccc, 0x33333333, 0xcccccccc}, \
+		{0x99999999, 0x66666666, 0x99999999, 0x66666666, 0x99999999, 0x66666666, 0x99999999, 0x66666666}, \
+		{0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0}, \
+		{0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a}, \
+		{0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c}, \
+		{0x69696969, 0x96969696, 0x69696969, 0x96969696, 0x69696969, 0x96969696, 0x69696969, 0x96969696}, \
+		{0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0xff00ff00}, \
+		{0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0x55aa55aa}, \
+		{0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0x33cc33cc}, \
+		{0x66996699, 0x99669966, 0x66996699, 0x99669966, 0x66996699, 0x99669966, 0x66996699, 0x99669966}, \
+		{0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0}, \
+		{0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0xa55aa55a}, \
+		{0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0xc33cc33c}, \
+		{0x96699669, 0x69966996, 0x96699669, 0x69966996, 0x96699669, 0x69966996, 0x96699669, 0x69966996}, \
+		{0x0000ffff, 0xffff0000, 0x0000ffff, 0xffff0000, 0x0000ffff, 0xffff0000, 0x0000ffff, 0xffff0000}, \
+		{0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0x5555aaaa}, \
+		{0xcccc3333, 0x3333cccc, 0xcccc3333, 0x3333cccc, 0xcccc3333, 0x3333cccc, 0xcccc3333, 0x3333cccc}, \
+		{0x66669999, 0x99996666, 0x66669999, 0x99996666, 0x66669999, 0x99996666, 0x66669999, 0x99996666}, \
+		{0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0}, \
+		{0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a}, \
+		{0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c}, \
+		{0x96966969, 0x69699696, 0x96966969, 0x69699696, 0x96966969, 0x69699696, 0x96966969, 0x69699696}, \
+		{0xff0000ff, 0x00ffff00, 0xff0000ff, 0x00ffff00, 0xff0000ff, 0x00ffff00, 0xff0000ff, 0x00ffff00}, \
+		{0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0xaa5555aa}, \
+		{0x33cccc33, 0xcc3333cc, 0x33cccc33, 0xcc3333cc, 0x33cccc33, 0xcc3333cc, 0x33cccc33, 0xcc3333cc}, \
+		{0x99666699, 0x66999966, 0x99666699, 0x66999966, 0x99666699, 0x66999966, 0x99666699, 0x66999966}, \
+		{0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0}, \
+		{0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a}, \
+		{0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c}, \
+		{0x69969669, 0x96696996, 0x69969669, 0x96696996, 0x69969669, 0x96696996, 0x69969669, 0x96696996}, \
+		{0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}, \
+		{0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa}, \
+		{0x33333333, 0x33333333, 0xcccccccc, 0xcccccccc, 0x33333333, 0x33333333, 0xcccccccc, 0xcccccccc}, \
+		{0x99999999, 0x99999999, 0x66666666, 0x66666666, 0x99999999, 0x99999999, 0x66666666, 0x66666666}, \
+		{0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0}, \
+		{0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a}, \
+		{0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c}, \
+		{0x69696969, 0x69696969, 0x96969696, 0x96969696, 0x69696969, 0x69696969, 0x96969696, 0x96969696}, \
+		{0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0xff00ff00}, \
+		{0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0x55aa55aa}, \
+		{0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0x33cc33cc}, \
+		{0x66996699, 0x66996699, 0x99669966, 0x99669966, 0x66996699, 0x66996699, 0x99669966, 0x99669966}, \
+		{0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0}, \
+		{0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a}, \
+		{0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0xc33cc33c}, \
+		{0x96699669, 0x96699669, 0x69966996, 0x69966996, 0x96699669, 0x96699669, 0x69966996, 0x69966996}, \
+		{0x0000ffff, 0x0000ffff, 0xffff0000, 0xffff0000, 0x0000ffff, 0x0000ffff, 0xffff0000, 0xffff0000}, \
+		{0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0x5555aaaa}, \
+		{0xcccc3333, 0xcccc3333, 0x3333cccc, 0x3333cccc, 0xcccc3333, 0xcccc3333, 0x3333cccc, 0x3333cccc}, \
+		{0x66669999, 0x66669999, 0x99996666, 0x99996666, 0x66669999, 0x66669999, 0x99996666, 0x99996666}, \
+		{0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0}, \
+		{0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a}, \
+		{0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c}, \
+		{0x96966969, 0x96966969, 0x69699696, 0x69699696, 0x96966969, 0x96966969, 0x69699696, 0x69699696}, \
+		{0xff0000ff, 0xff0000ff, 0x00ffff00, 0x00ffff00, 0xff0000ff, 0xff0000ff, 0x00ffff00, 0x00ffff00}, \
+		{0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0xaa5555aa}, \
+		{0x33cccc33, 0x33cccc33, 0xcc3333cc, 0xcc3333cc, 0x33cccc33, 0x33cccc33, 0xcc3333cc, 0xcc3333cc}, \
+		{0x99666699, 0x99666699, 0x66999966, 0x66999966, 0x99666699, 0x99666699, 0x66999966, 0x66999966}, \
+		{0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0}, \
+		{0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a}, \
+		{0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c}, \
+		{0x69969669, 0x69969669, 0x96696996, 0x96696996, 0x69969669, 0x69969669, 0x96696996, 0x96696996}, \
+		{0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, \
+		{0xaaaaaaaa, 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, 0xaaaaaaaa}, \
+		{0xcccccccc, 0x33333333, 0x33333333, 0xcccccccc, 0xcccccccc, 0x33333333, 0x33333333, 0xcccccccc}, \
+		{0x66666666, 0x99999999, 0x99999999, 0x66666666, 0x66666666, 0x99999999, 0x99999999, 0x66666666}, \
+		{0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0}, \
+		{0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a}, \
+		{0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c}, \
+		{0x96969696, 0x69696969, 0x69696969, 0x96969696, 0x96969696, 0x69696969, 0x69696969, 0x96969696}, \
+		{0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0xff00ff00}, \
+		{0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa}, \
+		{0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc}, \
+		{0x99669966, 0x66996699, 0x66996699, 0x99669966, 0x99669966, 0x66996699, 0x66996699, 0x99669966}, \
+		{0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0}, \
+		{0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a}, \
+		{0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c}, \
+		{0x69966996, 0x96699669, 0x96699669, 0x69966996, 0x69966996, 0x96699669, 0x96699669, 0x69966996}, \
+		{0xffff0000, 0x0000ffff, 0x0000ffff, 0xffff0000, 0xffff0000, 0x0000ffff, 0x0000ffff, 0xffff0000}, \
+		{0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa}, \
+		{0x3333cccc, 0xcccc3333, 0xcccc3333, 0x3333cccc, 0x3333cccc, 0xcccc3333, 0xcccc3333, 0x3333cccc}, \
+		{0x99996666, 0x66669999, 0x66669999, 0x99996666, 0x99996666, 0x66669999, 0x66669999, 0x99996666}, \
+		{0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0}, \
+		{0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a}, \
+		{0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c}, \
+		{0x69699696, 0x96966969, 0x96966969, 0x69699696, 0x69699696, 0x96966969, 0x96966969, 0x69699696}, \
+		{0x00ffff00, 0xff0000ff, 0xff0000ff, 0x00ffff00, 0x00ffff00, 0xff0000ff, 0xff0000ff, 0x00ffff00}, \
+		{0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa}, \
+		{0xcc3333cc, 0x33cccc33, 0x33cccc33, 0xcc3333cc, 0xcc3333cc, 0x33cccc33, 0x33cccc33, 0xcc3333cc}, \
+		{0x66999966, 0x99666699, 0x99666699, 0x66999966, 0x66999966, 0x99666699, 0x99666699, 0x66999966}, \
+		{0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0}, \
+		{0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a}, \
+		{0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c}, \
+		{0x96696996, 0x69969669, 0x69969669, 0x96696996, 0x96696996, 0x69969669, 0x69969669, 0x96696996}, \
+		{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, \
+		{0x55555555, 0x55555555, 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa}, \
+		{0x33333333, 0x33333333, 0x33333333, 0x33333333, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc}, \
+		{0x99999999, 0x99999999, 0x99999999, 0x99999999, 0x66666666, 0x66666666, 0x66666666, 0x66666666}, \
+		{0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0}, \
+		{0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a}, \
+		{0xc3c3c3c3, 0xc3c3c3c3, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c}, \
+		{0x69696969, 0x69696969, 0x69696969, 0x69696969, 0x96969696, 0x96969696, 0x96969696, 0x96969696}, \
+		{0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00}, \
+		{0xaa55aa55, 0xaa55aa55, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa, 0x55aa55aa}, \
+		{0xcc33cc33, 0xcc33cc33, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc, 0x33cc33cc}, \
+		{0x66996699, 0x66996699, 0x66996699, 0x66996699, 0x99669966, 0x99669966, 0x99669966, 0x99669966}, \
+		{0xf00ff00f, 0xf00ff00f, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0, 0x0ff00ff0}, \
+		{0x5aa55aa5, 0x5aa55aa5, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a, 0xa55aa55a}, \
+		{0x3cc33cc3, 0x3cc33cc3, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c, 0xc33cc33c}, \
+		{0x96699669, 0x96699669, 0x96699669, 0x96699669, 0x69966996, 0x69966996, 0x69966996, 0x69966996}, \
+		{0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000}, \
+		{0xaaaa5555, 0xaaaa5555, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa, 0x5555aaaa}, \
+		{0xcccc3333, 0xcccc3333, 0xcccc3333, 0xcccc3333, 0x3333cccc, 0x3333cccc, 0x3333cccc, 0x3333cccc}, \
+		{0x66669999, 0x66669999, 0x66669999, 0x66669999, 0x99996666, 0x99996666, 0x99996666, 0x99996666}, \
+		{0xf0f00f0f, 0xf0f00f0f, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0, 0x0f0ff0f0}, \
+		{0x5a5aa5a5, 0x5a5aa5a5, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a, 0xa5a55a5a}, \
+		{0x3c3cc3c3, 0x3c3cc3c3, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c, 0xc3c33c3c}, \
+		{0x96966969, 0x96966969, 0x96966969, 0x96966969, 0x69699696, 0x69699696, 0x69699696, 0x69699696}, \
+		{0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x00ffff00, 0x00ffff00, 0x00ffff00, 0x00ffff00}, \
+		{0x55aaaa55, 0x55aaaa55, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa, 0xaa5555aa}, \
+		{0x33cccc33, 0x33cccc33, 0x33cccc33, 0x33cccc33, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc, 0xcc3333cc}, \
+		{0x99666699, 0x99666699, 0x99666699, 0x99666699, 0x66999966, 0x66999966, 0x66999966, 0x66999966}, \
+		{0x0ff0f00f, 0x0ff0f00f, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0, 0xf00f0ff0}, \
+		{0xa55a5aa5, 0xa55a5aa5, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a, 0x5aa5a55a}, \
+		{0xc33c3cc3, 0xc33c3cc3, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c, 0x3cc3c33c}, \
+		{0x69969669, 0x69969669, 0x69969669, 0x69969669, 0x96696996, 0x96696996, 0x96696996, 0x96696996}, \
+		{0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, \
+		{0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa}, \
+		{0xcccccccc, 0x33333333, 0xcccccccc, 0x33333333, 0x33333333, 0xcccccccc, 0x33333333, 0xcccccccc}, \
+		{0x66666666, 0x99999999, 0x66666666, 0x99999999, 0x99999999, 0x66666666, 0x99999999, 0x66666666}, \
+		{0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0}, \
+		{0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a}, \
+		{0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c}, \
+		{0x96969696, 0x69696969, 0x96969696, 0x69696969, 0x69696969, 0x96969696, 0x69696969, 0x96969696}, \
+		{0xff00ff00, 0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0xff00ff00}, \
+		{0x55aa55aa, 0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0x55aa55aa}, \
+		{0x33cc33cc, 0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0x33cc33cc}, \
+		{0x99669966, 0x66996699, 0x99669966, 0x66996699, 0x66996699, 0x99669966, 0x66996699, 0x99669966}, \
+		{0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0}, \
+		{0xa55aa55a, 0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0xa55aa55a}, \
+		{0xc33cc33c, 0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0xc33cc33c}, \
+		{0x69966996, 0x96699669, 0x69966996, 0x96699669, 0x96699669, 0x69966996, 0x96699669, 0x69966996}, \
+		{0xffff0000, 0x0000ffff, 0xffff0000, 0x0000ffff, 0x0000ffff, 0xffff0000, 0x0000ffff, 0xffff0000}, \
+		{0x5555aaaa, 0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0x5555aaaa}, \
+		{0x3333cccc, 0xcccc3333, 0x3333cccc, 0xcccc3333, 0xcccc3333, 0x3333cccc, 0xcccc3333, 0x3333cccc}, \
+		{0x99996666, 0x66669999, 0x99996666, 0x66669999, 0x66669999, 0x99996666, 0x66669999, 0x99996666}, \
+		{0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0}, \
+		{0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a}, \
+		{0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c}, \
+		{0x69699696, 0x96966969, 0x69699696, 0x96966969, 0x96966969, 0x69699696, 0x96966969, 0x69699696}, \
+		{0x00ffff00, 0xff0000ff, 0x00ffff00, 0xff0000ff, 0xff0000ff, 0x00ffff00, 0xff0000ff, 0x00ffff00}, \
+		{0xaa5555aa, 0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0xaa5555aa}, \
+		{0xcc3333cc, 0x33cccc33, 0xcc3333cc, 0x33cccc33, 0x33cccc33, 0xcc3333cc, 0x33cccc33, 0xcc3333cc}, \
+		{0x66999966, 0x99666699, 0x66999966, 0x99666699, 0x99666699, 0x66999966, 0x99666699, 0x66999966}, \
+		{0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0}, \
+		{0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a}, \
+		{0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c}, \
+		{0x96696996, 0x69969669, 0x96696996, 0x69969669, 0x69969669, 0x96696996, 0x69969669, 0x96696996}, \
+		{0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}, \
+		{0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0xaaaaaaaa, 0xaaaaaaaa}, \
+		{0xcccccccc, 0xcccccccc, 0x33333333, 0x33333333, 0x33333333, 0x33333333, 0xcccccccc, 0xcccccccc}, \
+		{0x66666666, 0x66666666, 0x99999999, 0x99999999, 0x99999999, 0x99999999, 0x66666666, 0x66666666}, \
+		{0xf0f0f0f0, 0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0}, \
+		{0x5a5a5a5a, 0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a}, \
+		{0x3c3c3c3c, 0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c}, \
+		{0x96969696, 0x96969696, 0x69696969, 0x69696969, 0x69696969, 0x69696969, 0x96969696, 0x96969696}, \
+		{0xff00ff00, 0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xff00ff00, 0xff00ff00}, \
+		{0x55aa55aa, 0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa, 0x55aa55aa}, \
+		{0x33cc33cc, 0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc, 0x33cc33cc}, \
+		{0x99669966, 0x99669966, 0x66996699, 0x66996699, 0x66996699, 0x66996699, 0x99669966, 0x99669966}, \
+		{0x0ff00ff0, 0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0}, \
+		{0xa55aa55a, 0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a, 0xa55aa55a}, \
+		{0xc33cc33c, 0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c, 0xc33cc33c}, \
+		{0x69966996, 0x69966996, 0x96699669, 0x96699669, 0x96699669, 0x96699669, 0x69966996, 0x69966996}, \
+		{0xffff0000, 0xffff0000, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0xffff0000, 0xffff0000}, \
+		{0x5555aaaa, 0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa, 0x5555aaaa}, \
+		{0x3333cccc, 0x3333cccc, 0xcccc3333, 0xcccc3333, 0xcccc3333, 0xcccc3333, 0x3333cccc, 0x3333cccc}, \
+		{0x99996666, 0x99996666, 0x66669999, 0x66669999, 0x66669999, 0x66669999, 0x99996666, 0x99996666}, \
+		{0x0f0ff0f0, 0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0}, \
+		{0xa5a55a5a, 0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a}, \
+		{0xc3c33c3c, 0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c}, \
+		{0x69699696, 0x69699696, 0x96966969, 0x96966969, 0x96966969, 0x96966969, 0x69699696, 0x69699696}, \
+		{0x00ffff00, 0x00ffff00, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x00ffff00, 0x00ffff00}, \
+		{0xaa5555aa, 0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa, 0xaa5555aa}, \
+		{0xcc3333cc, 0xcc3333cc, 0x33cccc33, 0x33cccc33, 0x33cccc33, 0x33cccc33, 0xcc3333cc, 0xcc3333cc}, \
+		{0x66999966, 0x66999966, 0x99666699, 0x99666699, 0x99666699, 0x99666699, 0x66999966, 0x66999966}, \
+		{0xf00f0ff0, 0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0}, \
+		{0x5aa5a55a, 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a}, \
+		{0x3cc3c33c, 0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c}, \
+		{0x96696996, 0x96696996, 0x69969669, 0x69969669, 0x69969669, 0x69969669, 0x96696996, 0x96696996}, \
+		{0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000}, \
+		{0x55555555, 0xaaaaaaaa, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, 0x55555555, 0x55555555, 0xaaaaaaaa}, \
+		{0x33333333, 0xcccccccc, 0xcccccccc, 0x33333333, 0xcccccccc, 0x33333333, 0x33333333, 0xcccccccc}, \
+		{0x99999999, 0x66666666, 0x66666666, 0x99999999, 0x66666666, 0x99999999, 0x99999999, 0x66666666}, \
+		{0x0f0f0f0f, 0xf0f0f0f0, 0xf0f0f0f0, 0x0f0f0f0f, 0xf0f0f0f0, 0x0f0f0f0f, 0x0f0f0f0f, 0xf0f0f0f0}, \
+		{0xa5a5a5a5, 0x5a5a5a5a, 0x5a5a5a5a, 0xa5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5, 0xa5a5a5a5, 0x5a5a5a5a}, \
+		{0xc3c3c3c3, 0x3c3c3c3c, 0x3c3c3c3c, 0xc3c3c3c3, 0x3c3c3c3c, 0xc3c3c3c3, 0xc3c3c3c3, 0x3c3c3c3c}, \
+		{0x69696969, 0x96969696, 0x96969696, 0x69696969, 0x96969696, 0x69696969, 0x69696969, 0x96969696}, \
+		{0x00ff00ff, 0xff00ff00, 0xff00ff00, 0x00ff00ff, 0xff00ff00, 0x00ff00ff, 0x00ff00ff, 0xff00ff00}, \
+		{0xaa55aa55, 0x55aa55aa, 0x55aa55aa, 0xaa55aa55, 0x55aa55aa, 0xaa55aa55, 0xaa55aa55, 0x55aa55aa}, \
+		{0xcc33cc33, 0x33cc33cc, 0x33cc33cc, 0xcc33cc33, 0x33cc33cc, 0xcc33cc33, 0xcc33cc33, 0x33cc33cc}, \
+		{0x66996699, 0x99669966, 0x99669966, 0x66996699, 0x99669966, 0x66996699, 0x66996699, 0x99669966}, \
+		{0xf00ff00f, 0x0ff00ff0, 0x0ff00ff0, 0xf00ff00f, 0x0ff00ff0, 0xf00ff00f, 0xf00ff00f, 0x0ff00ff0}, \
+		{0x5aa55aa5, 0xa55aa55a, 0xa55aa55a, 0x5aa55aa5, 0xa55aa55a, 0x5aa55aa5, 0x5aa55aa5, 0xa55aa55a}, \
+		{0x3cc33cc3, 0xc33cc33c, 0xc33cc33c, 0x3cc33cc3, 0xc33cc33c, 0x3cc33cc3, 0x3cc33cc3, 0xc33cc33c}, \
+		{0x96699669, 0x69966996, 0x69966996, 0x96699669, 0x69966996, 0x96699669, 0x96699669, 0x69966996}, \
+		{0x0000ffff, 0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000, 0x0000ffff, 0x0000ffff, 0xffff0000}, \
+		{0xaaaa5555, 0x5555aaaa, 0x5555aaaa, 0xaaaa5555, 0x5555aaaa, 0xaaaa5555, 0xaaaa5555, 0x5555aaaa}, \
+		{0xcccc3333, 0x3333cccc, 0x3333cccc, 0xcccc3333, 0x3333cccc, 0xcccc3333, 0xcccc3333, 0x3333cccc}, \
+		{0x66669999, 0x99996666, 0x99996666, 0x66669999, 0x99996666, 0x66669999, 0x66669999, 0x99996666}, \
+		{0xf0f00f0f, 0x0f0ff0f0, 0x0f0ff0f0, 0xf0f00f0f, 0x0f0ff0f0, 0xf0f00f0f, 0xf0f00f0f, 0x0f0ff0f0}, \
+		{0x5a5aa5a5, 0xa5a55a5a, 0xa5a55a5a, 0x5a5aa5a5, 0xa5a55a5a, 0x5a5aa5a5, 0x5a5aa5a5, 0xa5a55a5a}, \
+		{0x3c3cc3c3, 0xc3c33c3c, 0xc3c33c3c, 0x3c3cc3c3, 0xc3c33c3c, 0x3c3cc3c3, 0x3c3cc3c3, 0xc3c33c3c}, \
+		{0x96966969, 0x69699696, 0x69699696, 0x96966969, 0x69699696, 0x96966969, 0x96966969, 0x69699696}, \
+		{0xff0000ff, 0x00ffff00, 0x00ffff00, 0xff0000ff, 0x00ffff00, 0xff0000ff, 0xff0000ff, 0x00ffff00}, \
+		{0x55aaaa55, 0xaa5555aa, 0xaa5555aa, 0x55aaaa55, 0xaa5555aa, 0x55aaaa55, 0x55aaaa55, 0xaa5555aa}, \
+		{0x33cccc33, 0xcc3333cc, 0xcc3333cc, 0x33cccc33, 0xcc3333cc, 0x33cccc33, 0x33cccc33, 0xcc3333cc}, \
+		{0x99666699, 0x66999966, 0x66999966, 0x99666699, 0x66999966, 0x99666699, 0x99666699, 0x66999966}, \
+		{0x0ff0f00f, 0xf00f0ff0, 0xf00f0ff0, 0x0ff0f00f, 0xf00f0ff0, 0x0ff0f00f, 0x0ff0f00f, 0xf00f0ff0}, \
+		{0xa55a5aa5, 0x5aa5a55a, 0x5aa5a55a, 0xa55a5aa5, 0x5aa5a55a, 0xa55a5aa5, 0xa55a5aa5, 0x5aa5a55a}, \
+		{0xc33c3cc3, 0x3cc3c33c, 0x3cc3c33c, 0xc33c3cc3, 0x3cc3c33c, 0xc33c3cc3, 0xc33c3cc3, 0x3cc3c33c}, \
+		{0x69969669, 0x96696996, 0x96696996, 0x69969669, 0x96696996, 0x69969669, 0x69969669, 0x96696996} };
+
+void readCodeWords(uint64_t** codewords) {
+	uint32_t i, j, k;
+	for(i = 0; i < m_nCodewords; i++) {
+		for(j = 0; j < (m_nCWIntlen * sizeof(uint32_t)) / sizeof(uint64_t); j++) {
+			codewords[i][j] = 0;
+			for(k = 0; k < sizeof(uint64_t) / sizeof(uint32_t); k++) {
+				codewords[i][j] |= (((uint64_t) CODE_MATRIX[i][j*sizeof(uint64_t) / sizeof(uint32_t)+k]) << (k * 8 * sizeof(uint32_t)));
+				//std::cout << (std::hex) << CODE_MATRIX[i][j*2+k];
+			}
+		//	std::cout << (std::hex) << codewords[i][j] << ", ";
+		}
+		//std::cout << std::endl;
+	}
+}
+
+void InitAndReadCodeWord(uint64_t*** codewords) {
+	uint32_t ncodewords = m_nCodeWordBits;
+	uint32_t ncwintlen = 8;
+	*codewords = (uint64_t**) malloc(sizeof(uint64_t*) * ncodewords);
+	for(uint32_t i = 0; i < ncodewords; i++) {
+		(*codewords)[i] = (uint64_t*) malloc(sizeof(uint64_t) * ((ncwintlen * sizeof(uint32_t)) / sizeof(uint64_t)));
+	}
+	readCodeWords(*codewords);
+}

+ 36 - 0
2p-preprocessing/ENCRYPTO_utils/codewords.h

@@ -0,0 +1,36 @@
+/**
+ \file 		codewords.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		A hard-coded Welsh-Hadamard code for up to 8-bit words and resulting 256-bit codewords
+ */
+
+#ifndef __CODEWORDS_H_
+#define __CODEWORDS_H_
+
+#include <cstdint>
+#include <cstdlib>
+
+const uint32_t m_nCodewords = 256;
+const uint32_t m_nCWIntlen = 8;
+
+const uint32_t m_nCodeWordBits = 256;
+const uint32_t m_nCodeWordBytes = m_nCodeWordBits/8;
+
+extern const uint32_t CODE_MATRIX[m_nCodewords][m_nCWIntlen];
+
+void readCodeWords(uint64_t** codewords);
+void InitAndReadCodeWord(uint64_t*** codewords);
+
+#endif //CODEWORDS_H_

+ 117 - 0
2p-preprocessing/ENCRYPTO_utils/connection.cpp

@@ -0,0 +1,117 @@
+/**
+ \file 		connection.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Connection Implementation
+ */
+
+#include "connection.h"
+#include "constants.h"
+#include "socket.h"
+#include "utils.h"
+#include <cassert>
+#include <iostream>
+#include <limits>
+
+bool Connect(const std::string& address, uint16_t port,
+		std::vector<std::unique_ptr<CSocket>> &sockets, uint32_t id) {
+#ifndef BATCH
+	std::cout << "Connecting party "<< id <<": " << address << ", " << port << std::endl;
+#endif
+	assert(sockets.size() <= std::numeric_limits<uint32_t>::max());
+	for (size_t j = 0; j < sockets.size(); j++) {
+		sockets[j] = Connect(address, port);
+		if (sockets[j]) {
+			// handshake
+			sockets[j]->Send(&id, sizeof(id));
+			uint32_t index = static_cast<uint32_t>(j);
+			sockets[j]->Send(&index, sizeof(index));
+		}
+		else {
+			return false;
+		}
+	}
+	return true;
+}
+
+bool Listen(const std::string& address, uint16_t port,
+		std::vector<std::vector<std::unique_ptr<CSocket>>> &sockets,
+		size_t numConnections, uint32_t myID) {
+
+	auto listen_socket = std::make_unique<CSocket>();
+
+	if (!listen_socket->Bind(address, port)) {
+		std::cerr << "Error: a socket could not be bound\n";
+		return false;
+	}
+	if (!listen_socket->Listen()) {
+		std::cerr << "Error: could not listen on the socket \n";
+		return false;
+	}
+
+	for (size_t i = 0; i < numConnections; i++)
+	{
+		auto sock = listen_socket->Accept();
+		if (!sock) {
+			std::cerr << "Error: could not accept connection\n";
+			return false;
+		}
+		// receive initial pid when connected
+		uint32_t nID;
+		uint32_t conID; //a mix of threadID and role - depends on the application
+		sock->Receive(&nID, sizeof(nID));
+		sock->Receive(&conID, sizeof(conID));
+
+		if (nID >= sockets.size()) //Not more than two parties currently allowed
+				{
+			sock->Close();
+			i--;  // try same index again
+			continue;
+		}
+		if (conID >= sockets[myID].size()) {
+			sock->Close();
+			i--;  // try same index again
+			continue;
+		}
+		// locate the socket appropriately
+		sockets[nID][conID] = std::move(sock);
+	}
+
+#ifndef BATCH
+	std::cout << "Listening finished" << std::endl;
+#endif
+	return true;
+}
+
+std::unique_ptr<CSocket> Connect(const std::string& address, uint16_t port) {
+	auto socket = std::make_unique<CSocket>();
+	for (int i = 0; i < RETRY_CONNECT; i++) {
+		if (socket->Connect(address, port))
+			return socket;
+		SleepMiliSec(10);
+	}
+	std::cerr << "Connect failed due to timeout!\n";
+	return nullptr;
+}
+
+std::unique_ptr<CSocket> Listen(const std::string& address, uint16_t port) {
+	auto listen_socket = std::make_unique<CSocket>();
+	if (!listen_socket->Bind(address, port)) {
+		return nullptr;
+	}
+	if (!listen_socket->Listen()) {
+		return nullptr;
+	}
+	return listen_socket->Accept();
+}

+ 39 - 0
2p-preprocessing/ENCRYPTO_utils/connection.h

@@ -0,0 +1,39 @@
+/**
+ \file 		connection.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		connection Implementation
+ */
+
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include "typedefs.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+// forward declaration
+class CSocket;
+
+bool Connect(const std::string& address, uint16_t port,
+		std::vector<std::unique_ptr<CSocket>> &sockets, uint32_t id);
+bool Listen(const std::string& address, uint16_t port,
+		std::vector<std::vector<std::unique_ptr<CSocket>>> &sockets,
+		size_t numConnections, uint32_t myID);
+
+std::unique_ptr<CSocket> Connect(const std::string& address, uint16_t port);
+std::unique_ptr<CSocket> Listen(const std::string& address, uint16_t port);
+
+#endif

+ 66 - 0
2p-preprocessing/ENCRYPTO_utils/constants.h

@@ -0,0 +1,66 @@
+/**
+ \file 		constants.h
+ \author	michael.zohner@ec-spride.de, daniel.demmler@crisp-da.de
+\copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		File containing all crypto and networking constants used throughout the source
+ */
+
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+#include "typedefs.h"
+#include <cstdint>
+
+#define BATCH
+//#define FIXED_KEY_AES_HASHING
+//#define USE_PIPELINED_AES_NI
+//#define SIMPLE_TRANSPOSE //activate the simple transpose, only required for benchmarking, not recommended
+
+#define AES_KEY_BITS			128
+#define AES_KEY_BYTES			16
+#define AES_BITS				128
+#define AES_BYTES				16
+#define LOG2_AES_BITS			ceil_log2(AES_BITS)
+
+#define SHA1_OUT_BYTES 20
+#define SHA256_OUT_BYTES 32
+#define SHA512_OUT_BYTES 64
+
+#define MAX_NUM_COMM_CHANNELS 256
+#define ADMIN_CHANNEL MAX_NUM_COMM_CHANNELS-1
+
+enum field_type {P_FIELD, ECC_FIELD, FIELD_LAST};
+
+static const seclvl ST = { 40, 80, 1024 };
+static const seclvl MT = { 40, 112, 2048 };
+static const seclvl LT = { 40, 128, 3072 };
+static const seclvl XLT = { 40, 192, 7680 };
+static const seclvl XXLT = { 40, 256, 15360 };
+
+const uint8_t m_vFixedKeyAESSeed[AES_KEY_BYTES] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
+/** \var m_vSeed
+ \brief Static seed for various testing functionalities
+ */
+const uint8_t m_vSeed[AES_KEY_BYTES] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
+
+inline const char* getFieldType(field_type ftype) {
+	switch (ftype) {
+	case P_FIELD: return "P_FIELD";
+	case ECC_FIELD: return "ECC_FIELD";
+	default: return "unknown field";
+	}
+}
+#endif /* _CONSTANTS_H_ */
+
+

+ 41 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/Config.h

@@ -0,0 +1,41 @@
+/**
+* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+* 
+* Copyright (c) 2012 - SCAPI (http://crypto.biu.ac.il/scapi)
+* This file is part of the SCAPI project.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+* 
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+* 
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+* 
+* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* 
+* We request that any publication and/or code referring to and/or based on SCAPI contain an appropriate citation to SCAPI, including a reference to
+* http://crypto.biu.ac.il/SCAPI.
+* 
+* SCAPI uses Crypto++, Miracl, NTL and Bouncy Castle. Please see these projects for any further licensing issues.
+* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+* 
+*/
+#include <emmintrin.h>
+
+/**
+* A configuration file that uses defines used by other files in the project.
+*
+* author: Cryptography and Computer Security Research Group Department of Computer Science Bar-Ilan University (Meital Levy)
+*/
+
+
+
+typedef __m128i block;
+
+#define SIZE_OF_BLOCK 16//size in bytes
+#define XOR_GATE 6//the truth table is 0110
+#define XOR_NOT_GATE 9// the truth table is 1001, can also use the optimization of FreeXor
+#define ONE_GATE 15//the truth table is 1111
+#define ZERO_BLOCK _mm_setzero_si128()//a zero block used in many cases

+ 576 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/TedKrovetzAesNiWrapperC.cpp

@@ -0,0 +1,576 @@
+#include "TedKrovetzAesNiWrapperC.h"
+#ifdef USE_PIPELINED_AES_NI
+
+#ifdef _WIN32
+#include "StdAfx.h"
+#endif
+
+void AES_128_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
+{
+    block x0,x1,x2;
+    //block *kp = (block *)&aesKey;
+	aesKey->rd_key[0] = x0 = _mm_loadu_si128((block*)userkey);
+    x2 = _mm_setzero_si128();
+	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;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 8);   aesKey->rd_key[4] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 16);  aesKey->rd_key[5] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 32);  aesKey->rd_key[6] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 64);  aesKey->rd_key[7] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 128); aesKey->rd_key[8] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 27);  aesKey->rd_key[9] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 54);  aesKey->rd_key[10] = x0;
+}
+
+
+
+void AES_192_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
+{
+    __m128i x0,x1,x2,x3,tmp,*kp = (block *)&aesKey;
+    kp[0] = x0 = _mm_loadu_si128((block*)userkey);
+    tmp = x3 = _mm_loadu_si128((block*)(userkey+16));
+    x2 = _mm_setzero_si128();
+    EXPAND192_STEP(1,1);
+    EXPAND192_STEP(4,4);
+    EXPAND192_STEP(7,16);
+    EXPAND192_STEP(10,64);
+}
+
+void AES_256_Key_Expansion(const unsigned char *userkey, AES_KEY *aesKey)
+{
+	__m128i x0, x1, x2, x3;/* , *kp = (block *)&aesKey;*/
+	aesKey->rd_key[0] = x0 = _mm_loadu_si128((block*)userkey);
+	aesKey->rd_key[1] = x3 = _mm_loadu_si128((block*)(userkey + 16));
+    x2 = _mm_setzero_si128();
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 1);  aesKey->rd_key[2] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 1);  aesKey->rd_key[3] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 2);  aesKey->rd_key[4] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 2);  aesKey->rd_key[5] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 4);  aesKey->rd_key[6] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 4);  aesKey->rd_key[7] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 8);  aesKey->rd_key[8] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 8);  aesKey->rd_key[9] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 16); aesKey->rd_key[10] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 16); aesKey->rd_key[11] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 32); aesKey->rd_key[12] = x0;
+	EXPAND_ASSIST(x3, x1, x2, x0, 170, 32); aesKey->rd_key[13] = x3;
+	EXPAND_ASSIST(x0, x1, x2, x3, 255, 64); aesKey->rd_key[14] = x0;
+}
+
+void AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *aesKey)
+{
+    if (bits == 128) {
+		AES_128_Key_Expansion(userKey, aesKey);
+    } else if (bits == 192) {
+		AES_192_Key_Expansion(userKey, aesKey);
+    } else if (bits == 256) {
+		AES_256_Key_Expansion(userKey, aesKey);
+    }
+
+	aesKey->rounds = 6 + bits / 32;
+}
+
+void AES_encryptC(block *in, block *out,  AES_KEY *aesKey)
+{
+	int j, rnds = ROUNDS(aesKey);
+	const __m128i *sched = ((__m128i *)(aesKey->rd_key));
+	__m128i tmp = _mm_load_si128((__m128i*)in);
+	tmp = _mm_xor_si128(tmp, sched[0]);
+	for (j = 1; j<rnds; j++)  tmp = _mm_aesenc_si128(tmp, sched[j]);
+	tmp = _mm_aesenclast_si128(tmp, sched[j]);
+	_mm_store_si128((__m128i*)out, tmp);
+}
+
+
+void AES_ecb_encrypt(block *blk,  AES_KEY *aesKey) {
+	unsigned j, rnds = ROUNDS(aesKey);
+	const block *sched = ((block *)(aesKey->rd_key));
+
+	*blk = _mm_xor_si128(*blk, sched[0]);
+	for (j = 1; j<rnds; ++j)
+		*blk = _mm_aesenc_si128(*blk, sched[j]);
+	*blk = _mm_aesenclast_si128(*blk, sched[j]);
+}
+
+void AES_ecb_encrypt_blks(block *blks, unsigned nblks,  AES_KEY *aesKey) {
+    unsigned i,j,rnds=ROUNDS(aesKey);
+	const block *sched = ((block *)(aesKey->rd_key));
+	for (i=0; i<nblks; ++i)
+	    blks[i] =_mm_xor_si128(blks[i], sched[0]);
+	for(j=1; j<rnds; ++j)
+	    for (i=0; i<nblks; ++i)
+		    blks[i] = _mm_aesenc_si128(blks[i], sched[j]);
+	for (i=0; i<nblks; ++i)
+	    blks[i] =_mm_aesenclast_si128(blks[i], sched[j]);
+}
+
+void AES_ecb_encrypt_blks_4(block *blks,  AES_KEY *aesKey) {
+	unsigned j, rnds = ROUNDS(aesKey);
+	const block *sched = ((block *)(aesKey->rd_key));
+	blks[0] = _mm_xor_si128(blks[0], sched[0]);
+	blks[1] = _mm_xor_si128(blks[1], sched[0]);
+	blks[2] = _mm_xor_si128(blks[2], sched[0]);
+	blks[3] = _mm_xor_si128(blks[3], sched[0]);
+
+	for (j = 1; j < rnds; ++j){
+		blks[0] = _mm_aesenc_si128(blks[0], sched[j]);
+		blks[1] = _mm_aesenc_si128(blks[1], sched[j]);
+		blks[2] = _mm_aesenc_si128(blks[2], sched[j]);
+		blks[3] = _mm_aesenc_si128(blks[3], sched[j]);
+	}
+	blks[0] = _mm_aesenclast_si128(blks[0], sched[j]);
+	blks[1] = _mm_aesenclast_si128(blks[1], sched[j]);
+	blks[2] = _mm_aesenclast_si128(blks[2], sched[j]);
+	blks[3] = _mm_aesenclast_si128(blks[3], sched[j]);
+}
+
+
+void AES_ecb_encrypt_blks_2_in_out(block *in, block *out, AES_KEY *aesKey) {
+
+	unsigned j, rnds = ROUNDS(aesKey);
+	const block *sched = ((block *)(aesKey->rd_key));
+
+	out[0] = _mm_xor_si128(in[0], sched[0]);
+	out[1] = _mm_xor_si128(in[1], sched[0]);
+
+	for (j = 1; j < rnds; ++j){
+		out[0] = _mm_aesenc_si128(out[0], sched[j]);
+		out[1] = _mm_aesenc_si128(out[1], sched[j]);
+
+	}
+	out[0] = _mm_aesenclast_si128(out[0], sched[j]);
+	out[1] = _mm_aesenclast_si128(out[1], sched[j]);
+}
+
+void AES_ecb_encrypt_blks_4_in_out(block *in, block *out,  AES_KEY *aesKey) {
+	unsigned j, rnds = ROUNDS(aesKey);
+	const block *sched = ((block *)(aesKey->rd_key));
+	//block temp[4];
+
+	out[0] = _mm_xor_si128(in[0], sched[0]);
+	out[1] = _mm_xor_si128(in[1], sched[0]);
+	out[2] = _mm_xor_si128(in[2], sched[0]);
+	out[3] = _mm_xor_si128(in[3], sched[0]);
+
+	for (j = 1; j < rnds; ++j){
+		out[0] = _mm_aesenc_si128(out[0], sched[j]);
+		out[1] = _mm_aesenc_si128(out[1], sched[j]);
+		out[2] = _mm_aesenc_si128(out[2], sched[j]);
+		out[3] = _mm_aesenc_si128(out[3], sched[j]);
+	}
+	out[0] = _mm_aesenclast_si128(out[0], sched[j]);
+	out[1] = _mm_aesenclast_si128(out[1], sched[j]);
+	out[2] = _mm_aesenclast_si128(out[2], sched[j]);
+	out[3] = _mm_aesenclast_si128(out[3], sched[j]);
+}
+
+void AES_ecb_encrypt_blks_4_in_out_ind_keys(block *in, block *out,  AES_KEY **aesKey, block** sched) {
+	unsigned j, rnds = ROUNDS(aesKey[0]);
+	sched[0] = ((block *)(aesKey[0][0].rd_key));
+	sched[1] = ((block *)(aesKey[0][1].rd_key));
+	sched[2] = ((block *)(aesKey[0][2].rd_key));
+	sched[3] = ((block *)(aesKey[0][3].rd_key));
+	//block temp[4];
+
+	out[0] = _mm_xor_si128(in[0], sched[0][0]);
+	out[1] = _mm_xor_si128(in[1], sched[1][0]);
+	out[2] = _mm_xor_si128(in[2], sched[2][0]);
+	out[3] = _mm_xor_si128(in[3], sched[3][0]);
+
+	for (j = 1; j < rnds; ++j){
+		out[0] = _mm_aesenc_si128(out[0], sched[0][j]);
+		out[1] = _mm_aesenc_si128(out[1], sched[1][j]);
+		out[2] = _mm_aesenc_si128(out[2], sched[2][j]);
+		out[3] = _mm_aesenc_si128(out[3], sched[3][j]);
+	}
+	out[0] = _mm_aesenclast_si128(out[0], sched[0][j]);
+	out[1] = _mm_aesenclast_si128(out[1], sched[1][j]);
+	out[2] = _mm_aesenclast_si128(out[2], sched[2][j]);
+	out[3] = _mm_aesenclast_si128(out[3], sched[3][j]);
+}
+
+
+void AES_ecb_encrypt_blks_4_in_out_par_ks(block *in, block *out,  const unsigned char* userkey) {
+	unsigned int j, rnds = 10;
+
+    block k0, k1, k2, k3, ktmp, k0tmp, k1tmp, k2tmp, k3tmp;
+	/*aesKey->rd_key[0] = x0 = _mm_loadu_si128((block*)userkey);
+    x2 = _mm_setzero_si128();
+	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;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 8);   aesKey->rd_key[4] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 16);  aesKey->rd_key[5] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 32);  aesKey->rd_key[6] = x0;
+	EXPAND_ASSIST(x0, x1, x2, x0, 255, 64);  aesKey->rd_key[7] = x0;
+	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;*/
+
+	/*sched[0] = ((block *)(aesKey[0]->rd_key));
+	sched[1] = ((block *)(aesKey[1]->rd_key));
+	sched[2] = ((block *)(aesKey[2]->rd_key));
+	sched[3] = ((block *)(aesKey[3]->rd_key));*/
+
+
+    k0 = _mm_loadu_si128((block*)userkey);
+	out[0] = _mm_xor_si128(in[0], k0);
+    k1 = _mm_loadu_si128((block*)(userkey+16));
+	out[1] = _mm_xor_si128(in[1], k1);
+    k2 = _mm_loadu_si128((block*)(userkey+32));
+	out[2] = _mm_xor_si128(in[2], k2);
+    k3 = _mm_loadu_si128((block*)(userkey+48));
+	out[3] = _mm_xor_si128(in[3], k3);
+
+	k0tmp = _mm_setzero_si128();
+	k1tmp = _mm_setzero_si128();
+	k2tmp = _mm_setzero_si128();
+	k3tmp = _mm_setzero_si128();
+
+	//First Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 1);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 1);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 1);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 1);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Second Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 2);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 2);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 2);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 2);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Third Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 4);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 4);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 4);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 4);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Fourth Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 8);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 8);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 8);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 8);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Fifth Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 16);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 16);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 16);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 16);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Sixth Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 32);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 32);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 32);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 32);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Seventh Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 64);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 64);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 64);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 64);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Eight Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 128);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 128);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 128);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 128);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+
+	//Ninth Round
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 27);
+	out[0] = _mm_aesenc_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 27);
+	out[1] = _mm_aesenc_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 27);
+	out[2] = _mm_aesenc_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 27);
+	out[3] = _mm_aesenc_si128(out[3], k3);
+
+	//Tenth Roundkey
+	EXPAND_ASSIST(k0, ktmp, k0tmp, k0, 255, 54);
+	out[0] = _mm_aesenclast_si128(out[0], k0);
+	EXPAND_ASSIST(k1, ktmp, k1tmp, k1, 255, 54);
+	out[1] = _mm_aesenclast_si128(out[1], k1);
+	EXPAND_ASSIST(k2, ktmp, k2tmp, k2, 255, 54);
+	out[2] = _mm_aesenclast_si128(out[2], k2);
+	EXPAND_ASSIST(k3, ktmp, k3tmp, k3, 255, 54);
+	out[3] = _mm_aesenclast_si128(out[3], k3);
+}
+
+void AES256_ecb_encrypt_blks_4_in_out_par_ks(block *in, block *out,  const unsigned char* userkey) {
+	unsigned int j, rnds = 14;
+
+	//four keys for even and odd-numbered rounds as well as temporary keys
+    block k0e, k1e, k2e, k3e, k0o, k1o, k2o, k3o, ktmp, k0tmp, k1tmp, k2tmp, k3tmp;
+
+    /*	__m128i x0, x1, x2, x3;
+	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;*/
+
+    //Zero-th Round
+    k0e = _mm_loadu_si128((block*)userkey);
+	out[0] = _mm_xor_si128(in[0], k0e);
+    k1e = _mm_loadu_si128((block*)(userkey+32));
+	out[1] = _mm_xor_si128(in[1], k1e);
+    k2e = _mm_loadu_si128((block*)(userkey+64));
+	out[2] = _mm_xor_si128(in[2], k2e);
+    k3e = _mm_loadu_si128((block*)(userkey+96));
+	out[3] = _mm_xor_si128(in[3], k3e);
+
+	k0tmp = _mm_setzero_si128();
+	k1tmp = _mm_setzero_si128();
+	k2tmp = _mm_setzero_si128();
+	k3tmp = _mm_setzero_si128();
+
+    //First Round
+    k0o = _mm_loadu_si128((block*)(userkey+16));
+    out[0] = _mm_aesenc_si128(out[0], k0o);
+    k1o = _mm_loadu_si128((block*)(userkey+48));
+    out[1] = _mm_aesenc_si128(out[1], k1o);
+    k2o = _mm_loadu_si128((block*)(userkey+80));
+    out[2] = _mm_aesenc_si128(out[2], k2o);
+    k3o = _mm_loadu_si128((block*)(userkey+112));
+    out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Second Round; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 1);  aesKey->rd_key[2] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 1);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 1);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 1);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 1);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Third Round; odd round: result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 1);  aesKey->rd_key[3] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 1);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 1);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 1);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 1);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Fourth Round; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 2);  aesKey->rd_key[4] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 2);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 2);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 2);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 2);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Fifth Round; odd round: result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 2);  aesKey->rd_key[5] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 2);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 2);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 2);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 2);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Sixth Round; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 4);  aesKey->rd_key[6] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 4);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 4);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 4);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 4);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Seventh Round: result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 4);  aesKey->rd_key[7] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 4);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 4);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 4);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 4);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Eigth Round; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 8);  aesKey->rd_key[8] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 8);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 8);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 8);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 8);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Ninth Round: odd result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 8);  aesKey->rd_key[9] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 8);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 8);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 8);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 8);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Tenth Round; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 16); aesKey->rd_key[10] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 16);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 16);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 16);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 16);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Eleventh Roundkey: odd result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 16); aesKey->rd_key[11] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 16);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 16);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 16);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 16);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Twelvth Roundkey; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 32); aesKey->rd_key[12] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 32);
+	out[0] = _mm_aesenc_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 32);
+	out[1] = _mm_aesenc_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 32);
+	out[2] = _mm_aesenc_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 32);
+	out[3] = _mm_aesenc_si128(out[3], k3e);
+
+	//Thirtheenth Roundkey: odd result is written in kio
+	//EXPAND_ASSIST(x3, x1, x2, x0, 170, 32); aesKey->rd_key[13] = x3;
+	EXPAND_ASSIST(k0o, ktmp, k0tmp, k0e, 170, 32);
+	out[0] = _mm_aesenc_si128(out[0], k0o);
+	EXPAND_ASSIST(k1o, ktmp, k1tmp, k1e, 170, 32);
+	out[1] = _mm_aesenc_si128(out[1], k1o);
+	EXPAND_ASSIST(k2o, ktmp, k2tmp, k2e, 170, 32);
+	out[2] = _mm_aesenc_si128(out[2], k2o);
+	EXPAND_ASSIST(k3o, ktmp, k3tmp, k3e, 170, 32);
+	out[3] = _mm_aesenc_si128(out[3], k3o);
+
+	//Fourteenth Roundkey; even round: result is written in kie
+	//EXPAND_ASSIST(x0, x1, x2, x3, 255, 64); aesKey->rd_key[14] = x0;
+	EXPAND_ASSIST(k0e, ktmp, k0tmp, k0o, 255, 64);
+	out[0] = _mm_aesenclast_si128(out[0], k0e);
+	EXPAND_ASSIST(k1e, ktmp, k1tmp, k1o, 255, 64);
+	out[1] = _mm_aesenclast_si128(out[1], k1e);
+	EXPAND_ASSIST(k2e, ktmp, k2tmp, k2o, 255, 64);
+	out[2] = _mm_aesenclast_si128(out[2], k2e);
+	EXPAND_ASSIST(k3e, ktmp, k3tmp, k3o, 255, 64);
+	out[3] = _mm_aesenclast_si128(out[3], k3e);
+}
+
+
+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]);
+	}
+
+}
+#endif

+ 85 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/TedKrovetzAesNiWrapperC.h

@@ -0,0 +1,85 @@
+/**
+* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*
+* Copyright(c) 2013 Ted Krovetz.
+* This file was taken from the SCAPI project, where it was taken from the file ocb.c written by Ted Krovetz.
+* Some changes and additions may have been made and only part of the file written by Ted Krovetz has been copied 
+* only for the use of this project.
+*
+* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*
+*/
+
+// Copyright(c) 2013 Ted Krovetz.
+
+
+
+
+#ifndef TED_FILE
+#define TED_FILE
+
+#include "../constants.h"
+
+#ifdef USE_PIPELINED_AES_NI
+
+#include <wmmintrin.h>
+#include "Config.h"
+
+
+#include <iostream>
+#include <stdlib.h>
+using namespace std;
+
+
+typedef struct { block rd_key[15]; int rounds; } AES_KEY;
+#define ROUNDS(ctx) ((ctx)->rounds)
+
+//output is written to v1, v2 and v3 are temporary variables, v4 is the previous key, shuff_const and aes_const are round/aes specific constants
+#define EXPAND_ASSIST(v1,v2,v3,v4,shuff_const,aes_const)                    \
+    v2 = _mm_aeskeygenassist_si128(v4, aes_const);                           \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3),              \
+                                         _mm_castsi128_ps(v1), 16));        \
+    v1 = _mm_xor_si128(v1,v3);                                              \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3),              \
+                                         _mm_castsi128_ps(v1), 140));       \
+    v1 = _mm_xor_si128(v1,v3);                                              \
+    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_4_in_out_ind_keys(block *in, block *out,  AES_KEY **aesKey, block** sched);
+void AES_ecb_encrypt_blks_4_in_out_par_ks(block *in, block *out,  const unsigned char* userkey);
+void AES256_ecb_encrypt_blks_4_in_out_par_ks(block *in, block *out,  const unsigned char* userkey);
+
+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
+#endif

+ 489 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/crypto.cpp

@@ -0,0 +1,489 @@
+/**
+ \file 		crypto.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+			(at your option) any later version.
+			ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Implementation of crypto primitive class
+ */
+
+#include "crypto.h"
+#include "../socket.h"
+#include <openssl/sha.h>
+#include <openssl/des.h>
+#include "ecc-pk-crypto.h"
+#include "gmp-pk-crypto.h"
+#include <cstring>
+#include <iostream>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utility>
+
+crypto::crypto(uint32_t symsecbits, uint8_t* seed) {
+	init(symsecbits, seed);
+}
+
+crypto::crypto(uint32_t symsecbits) {
+	uint8_t* seed = (uint8_t*) malloc(sizeof(uint8_t) * AES_BYTES);
+	gen_secure_random(seed, AES_BYTES);
+
+	init(symsecbits, seed);
+	free(seed);
+}
+
+crypto::~crypto() {
+	free_prf_state(&global_prf_state);
+	free(aes_hash_in_buf);
+	free(aes_hash_out_buf);
+	free(sha_hash_buf);
+	free(aes_hash_buf_y1);
+	free(aes_hash_buf_y2);
+
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	clean_aes_key(&aes_hash_key);
+	clean_aes_key(&aes_enc_key);
+	clean_aes_key(&aes_dec_key);
+#endif
+}
+
+void crypto::init(uint32_t symsecbits, uint8_t* seed) {
+	secparam = get_sec_lvl(symsecbits);
+
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	aes_hash_key = EVP_CIPHER_CTX_new();
+	aes_enc_key = EVP_CIPHER_CTX_new();
+	aes_dec_key = EVP_CIPHER_CTX_new();
+#endif
+
+	init_prf_state(&global_prf_state, seed);
+
+	aes_hash_in_buf = (uint8_t*) malloc(AES_BYTES);
+	aes_hash_out_buf = (uint8_t*) malloc(AES_BYTES);
+	aes_hash_buf_y1 = (uint8_t*) malloc(AES_BYTES);
+	aes_hash_buf_y2 = (uint8_t*) malloc(AES_BYTES);
+
+	if (secparam.symbits == ST.symbits) {
+		hash_routine = &sha1_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA1_OUT_BYTES);
+	} else if (secparam.symbits == MT.symbits) {
+		hash_routine = &sha256_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA256_OUT_BYTES);
+	} else if (secparam.symbits == LT.symbits) {
+		hash_routine = &sha256_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA256_OUT_BYTES);
+	} else if (secparam.symbits == XLT.symbits) {
+		hash_routine = &sha512_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA512_OUT_BYTES);
+	} else if (secparam.symbits == XXLT.symbits) {
+		hash_routine = &sha512_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA512_OUT_BYTES);
+	} else {
+		hash_routine = &sha256_hash;
+		sha_hash_buf = (uint8_t*) malloc(SHA256_OUT_BYTES);
+	}
+}
+
+pk_crypto* crypto::gen_field(field_type ftype) {
+	uint8_t* pkseed = (uint8_t*) malloc(sizeof(uint8_t) * (secparam.symbits >> 3));
+	gen_rnd(pkseed, secparam.symbits >> 3);
+	pk_crypto* ret;
+	if (ftype == P_FIELD)
+		ret = new prime_field(secparam, pkseed);
+	else
+		ret = new ecc_field(secparam, pkseed);
+	free(pkseed);
+	return ret;
+}
+
+void gen_rnd_bytes(prf_state_ctx* prf_state, uint8_t* resbuf, uint32_t nbytes) {
+	AES_KEY_CTX* aes_key;
+	uint64_t* rndctr;
+	uint8_t* tmpbuf;
+	uint32_t i, size;
+	int32_t dummy;
+
+	aes_key = &(prf_state->aes_key);
+	rndctr = prf_state->ctr;
+	size = ceil_divide(nbytes, AES_BYTES);
+	tmpbuf = (uint8_t*) malloc(sizeof(uint8_t) * size * AES_BYTES);
+
+	//TODO it might be better to store the result directly in resbuf but this would require the invoking routine to pad it to a multiple of AES_BYTES
+	for (i = 0; i < size; i++, rndctr[0]++) {
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+		EVP_EncryptUpdate(*aes_key, tmpbuf + i * AES_BYTES, &dummy, (uint8_t*) rndctr, AES_BYTES);
+#else
+		EVP_EncryptUpdate(aes_key, tmpbuf + i * AES_BYTES, &dummy, (uint8_t*) rndctr, AES_BYTES);
+#endif
+	}
+	memcpy(resbuf, tmpbuf, nbytes);
+
+	free(tmpbuf);
+}
+
+void crypto::gen_rnd(uint8_t* resbuf, uint32_t nbytes) {
+	std::lock_guard<std::mutex> lock(global_prf_state_mutex);
+	gen_rnd_bytes(&global_prf_state, resbuf, nbytes);
+}
+
+void crypto::gen_rnd_uniform(uint32_t* res, uint32_t mod) {
+	//pad to multiple of 4 bytes for uint32_t length
+	uint32_t nrndbytes = PadToMultiple(bits_in_bytes(secparam.symbits) + ceil_log2(mod), sizeof(uint32_t));
+	uint64_t bitsint = (8*sizeof(uint32_t));
+	uint32_t rnditers = ceil_divide(nrndbytes * 8, bitsint);
+
+	uint32_t* rndbuf = (uint32_t*) malloc(nrndbytes);
+	gen_rnd((uint8_t*) rndbuf, nrndbytes);
+
+	uint64_t tmpval = 0, tmpmod = mod;
+
+	for(uint32_t i = 0; i < rnditers; i++) {
+		tmpval = (((uint64_t) (tmpval << bitsint)) | ((uint64_t)rndbuf[i]));
+		tmpval %= tmpmod;
+	}
+	*res = (uint32_t) tmpval;
+	free(rndbuf);
+}
+void crypto::gen_rnd_from_seed(uint8_t* resbuf, uint32_t resbytes, uint8_t* seed) {
+	prf_state_ctx tmpstate;
+	init_prf_state(&tmpstate, seed);
+	gen_rnd_bytes(&tmpstate, resbuf, resbytes);
+	free_prf_state(&tmpstate);
+}
+
+void crypto::encrypt(AES_KEY_CTX* enc_key, uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes) {
+	int32_t dummy;
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	EVP_EncryptUpdate(*enc_key, resbuf, &dummy, inbuf, ninbytes);
+#else
+	EVP_EncryptUpdate(enc_key, resbuf, &dummy, inbuf, ninbytes);
+#endif
+	//EVP_EncryptFinal_ex(enc_key, resbuf, &dummy);
+}
+void crypto::decrypt(AES_KEY_CTX* dec_key, uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes) {
+	int32_t dummy;
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	EVP_DecryptUpdate(*dec_key, resbuf, &dummy, inbuf, ninbytes);
+#else
+	EVP_DecryptUpdate(dec_key, resbuf, &dummy, inbuf, ninbytes);
+#endif
+	//EVP_DecryptFinal_ex(dec_key, resbuf, &dummy);
+}
+
+void crypto::encrypt(uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes) {
+	encrypt(&aes_enc_key, resbuf, inbuf, ninbytes);
+}
+
+void crypto::decrypt(uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes) {
+	decrypt(&aes_dec_key, resbuf, inbuf, ninbytes);
+}
+
+void crypto::seed_aes_hash(uint8_t* seed, bc_mode mode, const uint8_t* iv) {
+	seed_aes_key(&aes_hash_key, seed, mode, iv);
+}
+
+void crypto::seed_aes_enc(uint8_t* seed, bc_mode mode, const uint8_t* iv) {
+	seed_aes_key(&aes_enc_key, seed, mode, iv, true);
+	seed_aes_key(&aes_dec_key, seed, mode, iv, false);
+}
+
+void crypto::init_aes_key(AES_KEY_CTX* aes_key, uint8_t* seed, bc_mode mode, const uint8_t* iv) {
+	seed_aes_key(aes_key, seed, mode, iv);
+}
+
+void crypto::init_aes_key(AES_KEY_CTX* aes_key, uint32_t symbits, uint8_t* seed, bc_mode mode, const uint8_t* iv, bool encrypt) {
+	seed_aes_key(aes_key, symbits, seed, mode, iv, encrypt);
+}
+
+void crypto::seed_aes_key(AES_KEY_CTX* aeskey, uint8_t* seed, bc_mode mode, const uint8_t* iv, bool encrypt) {
+	seed_aes_key(aeskey, secparam.symbits, seed, mode, iv, encrypt);
+}
+
+void crypto::clean_aes_key(AES_KEY_CTX* aeskey) {
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	EVP_CIPHER_CTX_free(*aeskey);
+#else
+	EVP_CIPHER_CTX_cleanup(aeskey);
+#endif
+}
+
+void crypto::seed_aes_key(AES_KEY_CTX* aeskey, uint32_t symbits, uint8_t* seed, bc_mode mode, const uint8_t* iv, bool encrypt) {
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	*aeskey = EVP_CIPHER_CTX_new();
+	AES_KEY_CTX aes_key_tmp = *aeskey;
+#else
+	EVP_CIPHER_CTX_init(aeskey);
+	AES_KEY_CTX* aes_key_tmp = aeskey;
+#endif
+	int (*initfct)(EVP_CIPHER_CTX*, const EVP_CIPHER*, ENGINE*, const unsigned char*, const unsigned char*);
+
+	if (encrypt)
+		initfct = EVP_EncryptInit_ex;
+	else
+		initfct = EVP_DecryptInit_ex;
+
+	switch (mode) {
+	case ECB:
+		if (symbits <= 128) {
+			initfct(aes_key_tmp, EVP_aes_128_ecb(), NULL, seed, iv);
+		} else if(symbits == 192) {
+			initfct(aes_key_tmp, EVP_aes_192_ecb(), NULL, seed, iv);
+		} else {
+			initfct(aes_key_tmp, EVP_aes_256_ecb(), NULL, seed, iv);
+		}
+		break;
+	case CBC:
+		if (symbits <= 128) {
+			initfct(aes_key_tmp, EVP_aes_128_cbc(), NULL, seed, iv);
+		} else if(symbits == 192) {
+			initfct(aes_key_tmp, EVP_aes_192_cbc(), NULL, seed, iv);
+		} else {
+			initfct(aes_key_tmp, EVP_aes_256_cbc(), NULL, seed, iv);
+		}
+		break;
+	default:
+		if (symbits <= 128) {
+			initfct(aes_key_tmp, EVP_aes_128_ecb(), NULL, seed, iv);
+		} else if(symbits == 192) {
+			initfct(aes_key_tmp, EVP_aes_192_ecb(), NULL, seed, iv);
+		} else {
+			initfct(aes_key_tmp, EVP_aes_256_ecb(), NULL, seed, iv);
+		}
+		break;
+	}
+}
+
+void crypto::hash_ctr(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint64_t ctr) {
+	uint8_t* tmpbuf = (uint8_t*) malloc(ninbytes + sizeof(uint64_t));
+	memcpy(tmpbuf, &ctr, sizeof(uint64_t));
+	memcpy(tmpbuf + sizeof(uint64_t), inbuf, ninbytes);
+	hash_routine(resbuf, noutbytes, tmpbuf, ninbytes+sizeof(uint64_t), sha_hash_buf);
+	free(tmpbuf);
+}
+
+void crypto::hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes) {
+	uint8_t* hash_buf = (uint8_t*) malloc(get_hash_bytes());
+	hash_routine(resbuf, noutbytes, inbuf, ninbytes, hash_buf);
+	free(hash_buf);
+}
+
+void crypto::hash_buf(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* buf) {
+	hash_routine(resbuf, noutbytes, inbuf, ninbytes, buf);
+}
+
+void crypto::hash_non_threadsafe(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes) {
+	hash_routine(resbuf, noutbytes, inbuf, ninbytes, sha_hash_buf);
+}
+
+//A fixed-key hashing scheme that uses AES, should not be used for real hashing, hashes to AES_BYTES bytes
+//TODO not thread safe
+void crypto::fixed_key_aes_hash(AES_KEY_CTX* aes_key, uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes) {
+	int32_t dummy;
+
+	memset(aes_hash_in_buf, 0, AES_BYTES);
+	memcpy(aes_hash_in_buf, inbuf, ninbytes);
+
+	//two encryption iterations TODO: not secure since both blocks are treated independently, implement DM or MMO
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+	EVP_EncryptUpdate(*aes_key, aes_hash_out_buf, &dummy, aes_hash_in_buf, AES_BYTES);
+#else
+	EVP_EncryptUpdate(aes_key, aes_hash_out_buf, &dummy, aes_hash_in_buf, AES_BYTES);
+#endif
+
+	((uint64_t*) aes_hash_out_buf)[0] ^= ((uint64_t*) aes_hash_in_buf)[0];
+	((uint64_t*) aes_hash_out_buf)[1] ^= ((uint64_t*) aes_hash_in_buf)[1];
+
+	memcpy(resbuf, aes_hash_out_buf, noutbytes);
+}
+
+//Generate a random permutation of neles elements using Knuths algorithm
+void crypto::gen_rnd_perm(uint32_t* perm, uint32_t neles) {
+	uint32_t* rndbuf = (uint32_t*) malloc(sizeof(uint32_t) * neles);
+	uint32_t i, j;
+	//TODO Generate random numbers (CAREFUL: NOT UNIFORM)
+	gen_rnd((uint8_t*) rndbuf, sizeof(uint32_t) * neles);
+	for (i = 0; i < neles; i++) {
+		perm[i] = i;
+	}
+	for (i = 0; i < neles; i++) {
+		j = rndbuf[i] % neles; //NOT UNIFORM
+		std::swap(perm[i], perm[j]);
+	}
+	free(rndbuf);
+}
+
+uint32_t crypto::get_aes_key_bytes() {
+	if (secparam.symbits == ST.symbits)
+		return 16;
+	else if (secparam.symbits == MT.symbits)
+		return 16;
+	else if (secparam.symbits == LT.symbits)
+		return 16;
+	else if (secparam.symbits == XLT.symbits)
+		return 24;
+	else if (secparam.symbits == XXLT.symbits)
+		return 32;
+	else
+		return 64;
+}
+
+uint32_t crypto::get_hash_bytes() {
+	if (secparam.symbits == ST.symbits)
+		return 20;
+	else if (secparam.symbits == MT.symbits)
+		return 32;
+	else if (secparam.symbits == LT.symbits)
+		return 32;
+	else if (secparam.symbits == XLT.symbits)
+		return 64;
+	else if (secparam.symbits == XXLT.symbits)
+		return 64;
+	else
+		return 64;
+}
+
+//Generate a common seed, is only secure in the semi-honest model
+void crypto::gen_common_seed(prf_state_ctx* prf_state, CSocket& sock) {
+	uint8_t *seed_buf, *seed_rcv_buf;
+	uint32_t seed_bytes, i;
+
+	seed_bytes = get_aes_key_bytes();
+	seed_buf = (uint8_t*) malloc(seed_bytes);
+	seed_rcv_buf = (uint8_t*) malloc(seed_bytes);
+
+	//randomly generate and exchange seed bytes:
+	gen_rnd(seed_buf, seed_bytes);
+	sock.Send(seed_buf, seed_bytes);
+	sock.Receive(seed_rcv_buf, seed_bytes);
+
+	//xor both seeds
+	for (i = 0; i < seed_bytes; i++) {
+		seed_buf[i] ^= seed_rcv_buf[i];
+	}
+
+	init_prf_state(prf_state, seed_buf);
+
+	free(seed_buf);
+	free(seed_rcv_buf);
+}
+
+void crypto::init_prf_state(prf_state_ctx* prf_state, uint8_t* seed) {
+	seed_aes_key(&(prf_state->aes_key), seed);
+	prf_state->ctr = (uint64_t*) calloc(ceil_divide(secparam.symbits, 8 * sizeof(uint64_t)), sizeof(uint64_t));
+}
+
+void crypto::free_prf_state(prf_state_ctx* prf_state) {
+	free(prf_state->ctr);
+	clean_aes_key(&(prf_state->aes_key));
+}
+
+void des_encrypt(uint8_t* resbuf, uint8_t* inbuf, uint8_t* key, bool encrypt) {
+	DES_cblock      keyblock;
+	DES_cblock		msgblock;
+	DES_cblock		outblock;
+	DES_key_schedule schedule;
+
+	memcpy(msgblock, inbuf, 8);
+	memcpy( keyblock, key,8);
+	DES_set_key( &keyblock, &schedule );
+
+	/* Encryption occurs here */
+	DES_ecb_encrypt(&msgblock, &outblock, &schedule, (int) encrypt);
+
+	memcpy(resbuf, outblock, 8);
+}
+
+
+void des3_encrypt(uint8_t* resbuf, uint8_t* inbuf, uint8_t* key, bool encrypt) {
+	DES_cblock      keyblock1, keyblock2, keyblock3;
+	DES_cblock		msgblock;
+	DES_cblock		outblock;
+	DES_key_schedule schedule1, schedule2, schedule3;
+
+	memcpy(msgblock, inbuf, 8);
+
+	memcpy( keyblock1, key,8);
+	memcpy( keyblock2, key+8,8);
+	memcpy( keyblock2, key+16,8);
+
+	DES_set_key( &keyblock1, &schedule1 );
+	DES_set_key( &keyblock2, &schedule2 );
+	DES_set_key( &keyblock3, &schedule3 );
+
+	/* Encryption occurs here */
+	DES_ecb3_encrypt(&msgblock, &outblock, &schedule1, &schedule2, &schedule2, (int) encrypt);
+
+	memcpy(resbuf, outblock, 8);
+}
+
+
+void sha1_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf) {
+	SHA_CTX sha;
+	SHA1_Init(&sha);
+	SHA1_Update(&sha, inbuf, ninbytes);
+	SHA1_Final(hash_buf, &sha);
+	memcpy(resbuf, hash_buf, noutbytes);
+}
+
+void sha256_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf) {
+	SHA256_CTX sha;
+	SHA256_Init(&sha);
+	SHA256_Update(&sha, inbuf, ninbytes);
+	SHA256_Final(hash_buf, &sha);
+	memcpy(resbuf, hash_buf, noutbytes);
+}
+
+void sha512_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf) {
+	SHA512_CTX sha;
+	SHA512_Init(&sha);
+	SHA512_Update(&sha, inbuf, ninbytes);
+	SHA512_Final(hash_buf, &sha);
+	memcpy(resbuf, hash_buf, noutbytes);
+}
+
+//Read random bytes from /dev/urandom
+void gen_secure_random(uint8_t* dest, uint32_t nbytes) {
+	int fd = open("/dev/urandom", O_RDONLY);
+	if (fd < 0)
+	{
+		std::cerr << "Unable to open /dev/urandom, exiting" << std::endl;
+		exit(0);
+	}
+	size_t bytectr = 0;
+	while (bytectr < nbytes) {
+		ssize_t result = read(fd, dest + bytectr, nbytes - bytectr);
+		if (result < 0) {
+			std::cerr << "Unable to read from /dev/urandom, exiting" << std::endl;
+			exit(0);
+		}
+		bytectr += static_cast<size_t>(result);
+	}
+	if (close(fd) < 0)
+	{
+		std::cerr << "Unable to close /dev/urandom" << std::endl;
+	}
+}
+
+
+seclvl get_sec_lvl(uint32_t symsecbits) {
+	if (symsecbits == ST.symbits)
+		return ST;
+	else if (symsecbits == MT.symbits)
+		return MT;
+	else if (symsecbits == LT.symbits)
+		return LT;
+	else if (symsecbits == XLT.symbits)
+		return XLT;
+	else if (symsecbits == XXLT.symbits)
+		return XXLT;
+	else
+		return LT;
+}

+ 150 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/crypto.h

@@ -0,0 +1,150 @@
+/**
+ \file 		crypto.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+			(at your option) any later version.
+			ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Crypto primitive class
+ */
+
+#ifndef CRYPTO_H_
+#define CRYPTO_H_
+
+#include <openssl/evp.h>
+#include "../constants.h"
+#include <mutex>
+
+// forward declarations
+class pk_crypto;
+class CSocket;
+
+const uint8_t ZERO_IV[AES_BYTES] = { 0 };
+
+const uint8_t const_seed[2][16] = {{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF },
+		{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00 } };
+
+enum bc_mode {
+	ECB, CBC
+};
+
+//Check for the OpenSSL version number, since the EVP_CIPHER_CTX has become opaque from >= 1.1.0
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+	#define OPENSSL_OPAQUE_EVP_CIPHER_CTX
+#endif
+
+#ifdef OPENSSL_OPAQUE_EVP_CIPHER_CTX
+typedef EVP_CIPHER_CTX* AES_KEY_CTX;
+#else
+typedef EVP_CIPHER_CTX AES_KEY_CTX;
+#endif
+
+/* Predefined security levels,
+ * ST (SHORTTERM) = 1024/160/163 bit public key, 80 bit private key
+ * MT (MEDIUMTERM) = 2048/192/233 bit public key, 112 bit private key
+ * LT (LONGTERM) = 3072/256/283 bit public key, 128 bit private key
+ * XLT (EXTRA LONGTERM) = 7680/384/409 bit public key, 192 bit private key
+ * XXLT (EXTRA EXTRA LONGTERM) = 15360/512/571 bit public key, 256 bit private key
+ */
+
+struct prf_state_ctx {
+	AES_KEY_CTX aes_key;
+	uint64_t* ctr;
+};
+
+//TODO: not thread-safe when multiple threads generate random data using the same seed
+class crypto {
+
+public:
+
+	crypto(uint32_t symsecbits, uint8_t* seed);
+	crypto(uint32_t symsecbits);
+	~crypto();
+
+	//Randomness generation routines
+	void gen_rnd(uint8_t* resbuf, uint32_t numbytes);
+	void gen_rnd_from_seed(uint8_t* resbuf, uint32_t resbytes, uint8_t* seed);
+	//void gen_rnd(prf_state_ctx* prf_state, uint8_t* resbuf, uint32_t nbytes);
+	void gen_rnd_uniform(uint32_t* res, uint32_t mod);
+	void gen_rnd_perm(uint32_t* perm, uint32_t neles);
+
+	//Encryption routines
+	void encrypt(uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes);
+	void decrypt(uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes);
+
+	//Hash routines
+	void hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes);
+	void hash_buf(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* buf);
+	void hash_non_threadsafe(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes);
+	void hash_ctr(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint64_t ctr);
+	void fixed_key_aes_hash(AES_KEY_CTX* aes_key, uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes);
+	void fixed_key_aes_hash_ctr(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes);
+
+	//Key seed routines
+	void seed_aes_hash(uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV);
+	void seed_aes_enc(uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV);
+
+	//External encryption routines
+	void init_aes_key(AES_KEY_CTX* aes_key, uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV);
+	void init_aes_key(AES_KEY_CTX* aes_key, uint32_t symbits, uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV, bool encrypt = true);
+	void clean_aes_key(AES_KEY_CTX* aeskey);
+	uint32_t get_aes_key_bytes();
+	void encrypt(AES_KEY_CTX* enc_key, uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes);
+	void decrypt(AES_KEY_CTX* dec_key, uint8_t* resbuf, uint8_t* inbuf, uint32_t ninbytes);
+
+	pk_crypto* gen_field(field_type ftype);
+
+	seclvl get_seclvl() {
+		return secparam;
+	}
+	;
+	uint32_t get_hash_bytes();
+
+	void gen_common_seed(prf_state_ctx* aes_key, CSocket& sock);
+	void init_prf_state(prf_state_ctx* prf_state, uint8_t* seed);
+	void free_prf_state(prf_state_ctx* prf_state);
+private:
+	void seed_aes_key(AES_KEY_CTX* aeskey, uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV, bool encrypt = true);
+	void seed_aes_key(AES_KEY_CTX* aeskey, uint32_t symseclvl, uint8_t* seed, bc_mode mode = ECB, const uint8_t* iv = ZERO_IV, bool encrypt = true);
+	void init(uint32_t symsecbits, uint8_t* seed);
+
+
+	AES_KEY_CTX aes_hash_key;
+	AES_KEY_CTX aes_enc_key;
+	AES_KEY_CTX aes_dec_key;
+	prf_state_ctx global_prf_state;
+	std::mutex global_prf_state_mutex;
+
+	seclvl secparam;
+	uint8_t* aes_hash_in_buf;
+	uint8_t* aes_hash_out_buf;
+	uint8_t* aes_hash_buf_y1;
+	uint8_t* aes_hash_buf_y2;
+
+	uint8_t* sha_hash_buf;
+
+	void (*hash_routine)(uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*);
+};
+
+//Some functions that should be useable without the class
+void des_encrypt(uint8_t* resbuf, uint8_t* inbuf, uint8_t* key, bool encrypt);
+void des3_encrypt(uint8_t* resbuf, uint8_t* inbuf, uint8_t* key, bool encrypt);
+
+void sha1_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf);
+void sha256_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf);
+void sha512_hash(uint8_t* resbuf, uint32_t noutbytes, uint8_t* inbuf, uint32_t ninbytes, uint8_t* hash_buf);
+void gen_secure_random(uint8_t* dest, uint32_t nbytes);
+void gen_rnd_bytes(prf_state_ctx* prf_state, uint8_t* resbuf, uint32_t nbytes);
+
+seclvl get_sec_lvl(uint32_t symsecbits); //TODO pick a more elegant name (see crypto->get_seclvl())
+
+
+#endif /* CRYPTO_H_ */

+ 809 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/dgk.cpp

@@ -0,0 +1,809 @@
+/**
+ \file 		dgk.cpp
+ \author 	Daniel Demmler
+ \copyright Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+  This program 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 3 of the License, or
+  (at your option) any later version.
+  ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+
+ \brief		 libdgk - v0.9
+ A library implementing the DGK crypto system with full decryption
+ Thanks to Marina Blanton for sharing her Miracl DGK implementation from
+ M. Blanton and P. Gasti, "Secure and efficient protocols for iris and fingerprint identification" (ESORICS’11)
+ with us. We used it as a template for this GMP version.
+
+ The implementation structure was inspired by
+ libpailler - A library implementing the Paillier crypto system. (http://hms.isi.jhu.edu/acsc/libpaillier/)
+ */
+
+#include "dgk.h"
+#include "../powmod.h"
+#include "../utils.h"
+#include <cstdlib>
+#include <cstring>
+
+#define DGK_CHECKSIZE 0
+
+// number of test encryptions and decryptions that are performed to verify a generated key. This will take time, but more are better.
+#define KEYTEST_ITERATIONS 1000
+
+//array holding the powers of two
+mpz_t* powtwo;
+
+//array for holding temporary values
+mpz_t* gvpvqp;
+
+void dgk_complete_pubkey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, mpz_t n, mpz_t g, mpz_t h) {
+	*pub = (dgk_pubkey_t*) malloc(sizeof(dgk_pubkey_t));
+
+	mpz_init((*pub)->n);
+	mpz_init((*pub)->u);
+	mpz_init((*pub)->h);
+	mpz_init((*pub)->g);
+
+	mpz_set((*pub)->n, n);
+	mpz_setbit((*pub)->u, 2 * lbits + 2);
+	mpz_set((*pub)->g, g);
+	mpz_set((*pub)->h, h);
+
+	(*pub)->bits = modulusbits;
+	(*pub)->lbits = 2 * lbits + 2;
+}
+
+void dgk_keygen(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, dgk_prvkey_t** prv) {
+	mpz_t tmp, tmp2, f1, f2, exp1, exp2, exp3, xp, xq;
+
+	unsigned int found = 0, i;
+
+	//printf("Keygen %u %u\n", modulusbits, lbits);
+
+	/* allocate the new key structures */
+	*pub = (dgk_pubkey_t*) malloc(sizeof(dgk_pubkey_t));
+	*prv = (dgk_prvkey_t*) malloc(sizeof(dgk_prvkey_t));
+
+	/* initialize our integers */
+	mpz_init((*pub)->n);
+	mpz_init((*pub)->u);
+	mpz_init((*pub)->h);
+	mpz_init((*pub)->g);
+
+	mpz_init((*prv)->vp);
+	mpz_init((*prv)->vq);
+	mpz_init((*prv)->p);
+	mpz_init((*prv)->q);
+	mpz_init((*prv)->p_minusone);
+	mpz_init((*prv)->q_minusone);
+	mpz_init((*prv)->pinv);
+	mpz_init((*prv)->qinv);
+
+	mpz_inits(tmp, tmp2, f1, f2, exp1, exp2, exp3, xp, xq, NULL);
+
+	lbits = lbits * 2 + 2; // plaintext space needs to 2l+2 in our use case. probably not needed for general use, but four our MT generation.
+
+	(*pub)->bits = modulusbits;
+	(*pub)->lbits = lbits;
+
+	// vp and vq are primes
+	aby_prng((*prv)->vp, 160);
+	mpz_nextprime((*prv)->vp, (*prv)->vp);
+
+	aby_prng((*prv)->vq, 160);
+	do {
+		mpz_nextprime((*prv)->vq, (*prv)->vq);
+	} while (mpz_cmp((*prv)->vp, (*prv)->vq) == 0);
+
+	// u = 2^lbits. u is NOT a prime (different from original DGK to allow full and easy decryption. See Blanton/Gasti Paper for details).
+	mpz_setbit((*pub)->u, lbits);
+
+	// p
+	while (!found) {
+		aby_prng(f1, modulusbits / 2 - 160 - lbits);
+		mpz_nextprime(f1, f1);
+
+		mpz_mul((*prv)->p, (*pub)->u, (*prv)->vp);
+		mpz_mul((*prv)->p, f1, (*prv)->p);
+		mpz_add_ui((*prv)->p, (*prv)->p, 1);
+		found = mpz_probab_prime_p((*prv)->p, 50);
+	}
+	found = 0;
+
+	// q
+	while (!found) {
+		aby_prng(f2, modulusbits / 2 - 159 - lbits);
+		mpz_nextprime(f2, f2);
+
+		mpz_mul((*prv)->q, (*pub)->u, (*prv)->vq);
+		mpz_mul((*prv)->q, f2, (*prv)->q);
+		mpz_add_ui((*prv)->q, (*prv)->q, 1);
+		found = mpz_probab_prime_p((*prv)->q, 50);
+	}
+	found = 0;
+
+	// p-1, q-1 - this is currently not used
+	mpz_sub_ui((*prv)->p_minusone, (*prv)->p, 1);
+	mpz_sub_ui((*prv)->q_minusone, (*prv)->q, 1);
+
+	// n = pq
+	mpz_mul((*pub)->n, (*prv)->p, (*prv)->q);
+
+	mpz_setbit(exp1, lbits - 1);
+
+	mpz_mul(exp1, (*prv)->vp, exp1);
+	mpz_mul(exp1, f1, exp1);
+	mpz_mul(exp2, (*prv)->vp, (*pub)->u);
+	mpz_mul(exp3, f1, (*pub)->u);
+
+	// xp
+	while (!found) {
+		aby_prng(xp, mpz_sizeinbase((*prv)->p, 2) + 128);
+		mpz_mod(xp, xp, (*prv)->p);
+
+		mpz_powm(tmp, xp, exp1, (*prv)->p);
+		if (mpz_cmp_ui(tmp, 1) != 0) {
+			mpz_powm(tmp, xp, exp2, (*prv)->p);
+			if (mpz_cmp_ui(tmp, 1) != 0) {
+				mpz_powm(tmp, xp, exp3, (*prv)->p);
+				if (mpz_cmp_ui(tmp, 1) != 0) {
+					found = 1;
+				}
+			}
+		}
+	}
+	found = 0;
+
+	mpz_setbit(exp1, lbits - 1);
+
+	mpz_mul(exp1, (*prv)->vq, exp1);
+	mpz_mul(exp1, f2, exp1);
+	mpz_mul(exp2, (*prv)->vq, (*pub)->u);
+	mpz_mul(exp3, f2, (*pub)->u);
+
+	// xq
+	while (!found) {
+		aby_prng(xq, mpz_sizeinbase((*prv)->q, 2) + 128);
+		mpz_mod(xq, xq, (*prv)->q);
+
+		mpz_powm(tmp, xq, exp1, (*prv)->q);
+		if (mpz_cmp_ui(tmp, 1) != 0) {
+			mpz_powm(tmp, xq, exp2, (*prv)->q);
+			if (mpz_cmp_ui(tmp, 1) != 0) {
+				mpz_powm(tmp, xq, exp3, (*prv)->q);
+				if (mpz_cmp_ui(tmp, 1) != 0) {
+					found = 1;
+				}
+			}
+		}
+	}
+
+	// compute CRT: g = xp*q*(q^{-1} mod p) + xq*p*(p^{-1} mod q) mod n
+	mpz_invert(tmp, (*prv)->q, (*prv)->p); // tmp = 1/q % p
+	mpz_set((*prv)->qinv, tmp);
+	mpz_mul(tmp, tmp, (*prv)->q); // tmp = tmp * q
+
+	// tmp = xp*tmp % n
+	mpz_mul(tmp, xp, tmp);
+	mpz_mod(tmp, tmp, (*pub)->n);
+
+	mpz_invert(tmp2, (*prv)->p, (*prv)->q); // tmp1 = 1/p % q
+	mpz_set((*prv)->pinv, tmp2);
+	mpz_mul(tmp2, tmp2, (*prv)->p); // tmp1 = tmp1*p
+
+	// tmp1 = xq*tmp1 % n
+	mpz_mul(tmp2, xq, tmp2);
+	mpz_mod(tmp2, tmp2, (*pub)->n);
+
+	// g = xp + xq % n
+	mpz_add((*pub)->g, xq, xp);
+	mpz_mod((*pub)->g, (*pub)->g, (*pub)->n);
+
+	mpz_mul(tmp, f1, f2); // tmp = f1*f2
+	mpz_powm((*pub)->g, (*pub)->g, tmp, (*pub)->n); // g = g^tmp % n
+
+	aby_prng((*pub)->h, mpz_sizeinbase((*pub)->n, 2) + 128);
+	mpz_mod((*pub)->h, (*pub)->h, (*pub)->n);
+
+	mpz_mul(tmp, tmp, (*pub)->u);
+	mpz_powm((*pub)->h, (*pub)->h, tmp, (*pub)->n); // h = h^tmp % n
+
+	powtwo = (mpz_t*) malloc(sizeof(mpz_t) * lbits);
+	gvpvqp = (mpz_t*) malloc(sizeof(mpz_t) * lbits);
+
+	// array holding powers of two
+	for (i = 0; i < lbits; i++) {
+		mpz_init(powtwo[i]);
+		mpz_setbit(powtwo[i], i);
+	}
+
+	mpz_powm(f1, (*pub)->g, (*prv)->vp, (*prv)->p); // gvpvq
+
+	mpz_sub_ui(tmp2, (*pub)->u, 1); // tmp1 = u - 1
+
+	for (i = 0; i < lbits; i++) {
+		mpz_init(gvpvqp[i]);
+		mpz_powm(gvpvqp[i], f1, powtwo[i], (*prv)->p);
+		mpz_powm(gvpvqp[i], gvpvqp[i], tmp2, (*prv)->p);
+	}
+
+	/* clear temporary integers */
+	mpz_clears(tmp, tmp2, f1, f2, exp1, exp2, exp3, xp, xq, NULL);
+}
+
+void dgk_encrypt_db(mpz_t res, dgk_pubkey_t* pub, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DGK_CHECKSIZE
+	mpz_setbit(r, (pub->lbits-2)/2);
+	if (mpz_cmp(plaintext, r) >= 0) {
+		gmp_printf("m: %Zd\nmax:%Zd\n", plaintext, r);
+		printf("DGK WARNING: m too big!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, 400); // 2.5 * 160 = 400 bit
+
+	dbpowmod(res, pub->h, r, pub->g, plaintext, pub->n);
+
+	mpz_clear(r);
+}
+
+void dgk_encrypt_fb(mpz_t res, dgk_pubkey_t* pub, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DGK_CHECKSIZE
+	mpz_setbit(r, (pub->lbits-2)/2);
+	if (mpz_cmp(plaintext, r) >= 0) {
+		gmp_printf("m: %Zd\nmax:%Zd\n", plaintext, r);
+		printf("DGK WARNING: m too big!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, 400); // 2.5 * 160 = 400 bit
+	fbpowmod_h(r, r); //r = h^r
+	fbpowmod_g(res, plaintext); //res = g^plaintext
+
+	mpz_mul(res, res, r);
+	mpz_mod(res, res, pub->n);
+
+	mpz_clear(r);
+}
+
+void dgk_encrypt_plain(mpz_t res, dgk_pubkey_t* pub, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DGK_CHECKSIZE
+	mpz_setbit(r, (pub->lbits-2)/2);
+	if (mpz_cmp(plaintext, r) >= 0) {
+		gmp_printf("m: %Zd\nmax:%Zd\n", plaintext, r);
+		printf("DGK WARNING: m too big!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, 400); // 2.5 * 160 = 400 bit
+	mpz_powm(r, pub->h, r, pub->n);
+	mpz_powm(res, pub->g, plaintext, pub->n);
+
+	mpz_mul(res, res, r);
+	mpz_mod(res, res, pub->n);
+
+	mpz_clear(r);
+}
+
+void dgk_encrypt_crt_db(mpz_t res, dgk_pubkey_t * pub, dgk_prvkey_t * prv, mpz_t plaintext) {
+	mpz_t r, ep;
+	mpz_inits(r, ep, NULL);
+
+#if DGK_CHECKSIZE
+	mpz_setbit(r, (pub->lbits-2)/2);
+	if (mpz_cmp(plaintext, r) >= 0) {
+		gmp_printf("m: %Zd\nmax:%Zd\n", plaintext, r);
+		printf("DGK WARNING: m too big!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	//mpz_urandomb(r, rnd, 400); // 2.5 * 160 = 400 bit
+	aby_prng(r, 400);
+	dbpowmod(ep, pub->h, r, pub->g, plaintext, prv->p);
+
+	mpz_mul(res, ep, prv->q);
+	mpz_mul(res, res, prv->qinv);
+	mpz_mod(res, res, pub->n);
+
+	dbpowmod(ep, pub->h, r, pub->g, plaintext, prv->q);
+
+	mpz_mul(ep, ep, prv->p);
+	mpz_mul(ep, ep, prv->pinv);
+	mpz_mod(ep, ep, pub->n);
+
+	mpz_add(res, res, ep);
+	mpz_mod(res, res, pub->n);
+
+	mpz_clears(r, ep, NULL);
+}
+
+void dgk_encrypt_crt(mpz_t res, dgk_pubkey_t * pub, dgk_prvkey_t * prv, mpz_t plaintext) {
+	mpz_t r, ep, eq;
+	mpz_inits(r, ep, eq, NULL);
+
+#if DGK_CHECKSIZE
+	mpz_setbit(r, (pub->lbits-2)/2);
+	if (mpz_cmp(plaintext, r) >= 0) {
+		gmp_printf("m: %Zd\nmax:%Zd\n", plaintext, r);
+		printf("DGK WARNING: m too big!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, 400); // 2.5 * 160 = 400 bit
+	// ep = h^r * g^plaintext % p
+	mpz_powm(ep, pub->h, r, prv->p);
+	mpz_powm(res, pub->g, plaintext, prv->p);
+	mpz_mul(ep, ep, res);
+	mpz_mod(ep, ep, prv->p);
+
+	mpz_mul(res, ep, prv->q);
+	mpz_mul(res, res, prv->qinv);
+	mpz_mod(res, res, pub->n);
+
+	// ep = h^r*g^plaintext % q
+	mpz_powm(ep, pub->h, r, prv->q);
+	mpz_powm(eq, pub->g, plaintext, prv->q);
+	mpz_mul(ep, ep, eq);
+	mpz_mod(ep, ep, prv->q);
+
+	mpz_mul(ep, ep, prv->p);
+	mpz_mul(ep, ep, prv->pinv);
+	mpz_mod(ep, ep, pub->n);
+
+	mpz_add(res, res, ep);
+	mpz_mod(res, res, pub->n);
+
+	mpz_clears(r, ep, eq, NULL);
+}
+
+void dgk_decrypt(mpz_t res, dgk_pubkey_t* pub, dgk_prvkey_t* prv, mpz_t ciphertext) {
+	mpz_t y, yi;
+	mpz_inits(y, yi, NULL);
+
+	unsigned int i, xi[pub->lbits];
+
+	mpz_powm(y, ciphertext, prv->vp, prv->p);
+
+	mpz_set_ui(res, 0);
+
+	for (i = 0; i < pub->lbits; i++) {
+
+		mpz_powm(yi, y, powtwo[pub->lbits - 1 - i], prv->p);
+
+		if (mpz_cmp_ui(yi, 1) == 0) {
+			xi[i] = 0;
+		} else {
+			xi[i] = 1;
+
+			mpz_mul(y, y, gvpvqp[i]);
+			mpz_mod(y, y, prv->p);
+		}
+	}
+
+	for (i = 0; i < pub->lbits; i++) {
+		if (xi[i] == 1) {
+			mpz_add(res, powtwo[i], res);
+		}
+	}
+
+	mpz_clears(y, yi, NULL);
+}
+
+void dgk_freepubkey(dgk_pubkey_t* pub) {
+	mpz_clears(pub->n, pub->u, pub->g, pub->h, NULL);
+	free(pub);
+}
+
+void dgk_freeprvkey(dgk_prvkey_t* prv) {
+	mpz_clears(prv->p, prv->q, prv->vp, prv->vq, prv->qinv, prv->pinv, prv->p_minusone, prv->q_minusone, NULL);
+	free(prv);
+}
+
+void dgk_storekey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t* pub, dgk_prvkey_t* prv) {
+	FILE *fp;
+
+	char smod[5];
+	char slbit[4];
+	char name[40] = "dgk_key_";
+	const char* div = "_";
+	const char* ext = ".bin";
+
+	sprintf(smod, "%d", modulusbits);
+	sprintf(slbit, "%d", lbits);
+
+	strcat(name, smod);
+	strcat(name, div);
+	strcat(name, slbit);
+	strcat(name, ext);
+
+	printf("writing dgk key to %s\n", name);
+
+	fp = fopen(name, "w");
+
+	mpz_out_raw(fp, prv->p);
+	mpz_out_raw(fp, prv->q);
+	mpz_out_raw(fp, prv->vp);
+	mpz_out_raw(fp, prv->vq);
+
+	mpz_out_raw(fp, prv->pinv);
+	mpz_out_raw(fp, prv->qinv);
+
+	mpz_out_raw(fp, pub->n);
+	mpz_out_raw(fp, pub->u);
+	mpz_out_raw(fp, pub->g);
+	mpz_out_raw(fp, pub->h);
+
+	fclose(fp);
+}
+
+void dgk_readkey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, dgk_prvkey_t** prv) {
+	unsigned int i;
+
+	mpz_t f1, tmp;
+
+	mpz_inits(f1, tmp, NULL);
+
+	char smod[5];
+	char slbit[4];
+	char name[40] = "dgk_key_";
+	const char* div = "_";
+	const char* ext = ".bin";
+
+	sprintf(smod, "%d", modulusbits);
+	sprintf(slbit, "%d", lbits);
+
+	strcat(name, smod);
+	strcat(name, div);
+	strcat(name, slbit);
+	strcat(name, ext);
+
+//	printf("reading dgk key from %s\n", name);
+
+	/* allocate the new key structures */
+	*pub = (dgk_pubkey_t*) malloc(sizeof(dgk_pubkey_t));
+	*prv = (dgk_prvkey_t*) malloc(sizeof(dgk_prvkey_t));
+
+	FILE *fp;
+	fp = fopen(name, "r");
+
+	/* initialize our integers */
+	mpz_init((*pub)->n);
+	mpz_init((*pub)->u);
+	mpz_init((*pub)->h);
+	mpz_init((*pub)->g);
+
+	mpz_init((*prv)->vp);
+	mpz_init((*prv)->vq);
+	mpz_init((*prv)->p);
+	mpz_init((*prv)->q);
+
+	mpz_init((*prv)->pinv);
+	mpz_init((*prv)->qinv);
+
+	mpz_init((*prv)->p_minusone);
+	mpz_init((*prv)->q_minusone);
+
+	mpz_inp_raw((*prv)->p, fp);
+	mpz_inp_raw((*prv)->q, fp);
+	mpz_inp_raw((*prv)->vp, fp);
+	mpz_inp_raw((*prv)->vq, fp);
+	mpz_inp_raw((*prv)->pinv, fp);
+	mpz_inp_raw((*prv)->qinv, fp);
+
+	mpz_inp_raw((*pub)->n, fp);
+	mpz_inp_raw((*pub)->u, fp);
+	mpz_inp_raw((*pub)->g, fp);
+	mpz_inp_raw((*pub)->h, fp);
+
+	fclose(fp);
+
+	mpz_sub_ui((*prv)->p_minusone, (*prv)->p, 1);
+	mpz_sub_ui((*prv)->q_minusone, (*prv)->q, 1);
+
+	lbits = lbits * 2 + 2;
+
+	(*pub)->bits = modulusbits;
+	(*pub)->lbits = lbits;
+
+	powtwo = (mpz_t*) malloc(sizeof(mpz_t) * lbits);
+	gvpvqp = (mpz_t*) malloc(sizeof(mpz_t) * lbits);
+
+	// array holding powers of two
+	for (i = 0; i < lbits; i++) {
+		mpz_init(powtwo[i]);
+		mpz_setbit(powtwo[i], i);
+	}
+
+	mpz_powm(f1, (*pub)->g, (*prv)->vp, (*prv)->p); //gvpvq
+	mpz_sub_ui(tmp, (*pub)->u, 1); // tmp1 = u - 1
+
+	for (i = 0; i < lbits; i++) {
+		mpz_init(gvpvqp[i]);
+		mpz_powm(gvpvqp[i], f1, powtwo[i], (*prv)->p);
+		mpz_powm(gvpvqp[i], gvpvqp[i], tmp, (*prv)->p);
+	}
+
+	/*
+	 // debug output
+	 gmp_printf("n  %Zd\n", (*pub)->n);
+	 gmp_printf("u  %Zd\n", (*pub)->u);
+	 gmp_printf("g  %Zd\n", (*pub)->g);
+	 gmp_printf("h  %Zd\n", (*pub)->h);
+	 gmp_printf("p  %Zd\n", (*prv)->p);
+	 gmp_printf("q  %Zd\n", (*prv)->q);
+	 gmp_printf("vp %Zd\n", (*prv)->vp);
+	 gmp_printf("vq %Zd\n", (*prv)->vq);
+	 gmp_printf("vpinv %Zd\n", (*prv)->pinv);
+	 gmp_printf("vqinv %Zd\n", (*prv)->qinv);
+	 */
+}
+
+void createKeys() {
+	dgk_pubkey_t * pub;
+	dgk_prvkey_t * prv;
+
+	mpz_t msg, ct, msg2;
+
+	mpz_inits(msg, ct, msg2, NULL);
+
+	for (unsigned int n = 1024; n <= 3072; n += 1024) {
+		for (unsigned int l = 8; l <= 64; l *= 2) {
+
+			// choose either keygen or readkey
+			// dgk_keygen(n, l, &pub, &prv); //uncomment to acutally create keys
+			dgk_readkey(n, l, &pub, &prv); //only read from file
+
+			int no_error = 1;
+
+			if (l < 16) {
+				int maxit = 1 << l;
+				for (int i = 0; i < maxit; i++) {
+					mpz_set_ui(msg, i);
+					dgk_encrypt_plain(ct, pub, msg);
+					dgk_decrypt(msg2, pub, prv, ct);
+
+					if (mpz_cmp(msg, msg2)) {
+						//					printf("ERROR: \n");
+						//
+						//					gmp_printf("msg  %Zd\n", msg);
+						//					gmp_printf("ct   %Zd\n", ct);
+						//					gmp_printf("msg2 %Zd\n", msg2);
+						//
+						//					gmp_printf("n  %Zd\n", pub->n);
+						//					gmp_printf("u  %Zd\n", pub->u);
+						//					gmp_printf("g  %Zd\n", pub->g);
+						//					gmp_printf("h  %Zd\n", pub->h);
+						//					gmp_printf("p  %Zd\n", prv->p);
+						//					gmp_printf("q  %Zd\n", prv->q);
+						//					gmp_printf("vp %Zd\n", prv->vp);
+						//					gmp_printf("vq %Zd\n", prv->vq);
+						printf(".");
+						i = maxit;
+						no_error = 0;
+					}
+				}
+			} else {
+				for (int i = 0; i < KEYTEST_ITERATIONS; i++) {
+
+					if (i > 3) {
+						aby_prng(msg, l);
+					}
+					// test some corner cases first: 0, 1, 2^l-1, 2^l-2. After that random numbers.
+					else if (i == 0)
+						mpz_set_ui(msg, 0);
+					else if (i == 1)
+						mpz_set_ui(msg, 1);
+					else if (i == 2) {
+						mpz_set_ui(msg, 0);
+						mpz_setbit(msg, l);
+						mpz_sub_ui(msg, msg, 1);
+					} else if (i == 3) {
+						mpz_sub_ui(msg, msg, 1);
+					}
+
+					dgk_encrypt_plain(ct, pub, msg);
+					dgk_decrypt(msg2, pub, prv, ct);
+
+					if (mpz_cmp(msg, msg2)) {
+						// Error: decrypted message is different from encrypted message. We have to start again.
+						//					printf("ERROR: \n");
+						//
+						//					gmp_printf("msg  %Zd\n", msg);
+						//					gmp_printf("ct   %Zd\n", ct);
+						//					gmp_printf("msg2 %Zd\n", msg2);
+						//
+						//					gmp_printf("n  %Zd\n", pub->n);
+						//					gmp_printf("u  %Zd\n", pub->u);
+						//					gmp_printf("g  %Zd\n", pub->g);
+						//					gmp_printf("h  %Zd\n", pub->h);
+						//					gmp_printf("p  %Zd\n", prv->p);
+						//					gmp_printf("q  %Zd\n", prv->q);
+						//					gmp_printf("vp %Zd\n", prv->vp);
+						//					gmp_printf("vq %Zd\n", prv->vq);
+						printf(".");
+						no_error = 0;
+						break;
+					}
+				}
+			}
+			if (no_error) {
+				// dgk_storekey(n, l, pub, prv);
+			} else {
+				if (l > 4) { // re-do last iteration
+					l /= 2;
+				}
+			}
+		}
+	}
+}
+
+void test_encdec() {
+	dgk_pubkey_t * pub;
+	dgk_prvkey_t * prv;
+
+	mpz_t a0, a1, b0, b1, c0, c1, r, d, a0c, b0c, rc, tmp0, tmp1;
+
+	mpz_inits(a0, a1, b0, b1, c0, c1, r, d, a0c, b0c, rc, tmp0, tmp1, NULL);
+
+	unsigned int l = 32;
+	unsigned int nbit = 3072;
+
+	//choose either keygen or readkey
+	//dgk_keygen(nbit, l, &pub, &prv);
+	dgk_readkey(nbit, l, &pub, &prv);
+
+	aby_prng(a0, l);
+	dgk_encrypt_crt(a0c, pub, prv, a0); //encrypt a0
+
+	dgk_decrypt(b0, pub, prv, a0c);
+
+	if (mpz_cmp(a0, b0) == 0) {
+		printf("fine\n");
+	} else {
+		printf("ERR :(\n");
+		gmp_printf("%Zd, %Zd", a0, b0);
+	}
+
+	dgk_encrypt_plain(a0c, pub, a0);
+	dgk_decrypt(b0, pub, prv, a0c);
+
+	if (mpz_cmp(a0, b0) == 0) {
+		printf("fine\n");
+	} else {
+		printf("ERR :(\n");
+		gmp_printf("%Zd, %Zd", a0, b0);
+	}
+}
+
+void test_sharing() {
+	dgk_pubkey_t * pub;
+	dgk_prvkey_t * prv;
+
+	mpz_t a0, a1, b0, b1, c0, c1, r, d, a0c, b0c, rc, tmp0, tmp1;
+
+	mpz_inits(a0, a1, b0, b1, c0, c1, r, d, a0c, b0c, rc, tmp0, tmp1, NULL);
+
+	unsigned int l = 32;
+	unsigned int nbit = 3072;
+
+	//choose either keygen or readkey
+	// dgk_keygen(nbit, l, &pub, &prv);
+	dgk_readkey(nbit, l, &pub, &prv);
+
+	// choose random a and b shares, l bits long
+	aby_prng(a0, l);
+	aby_prng(b0, l);
+	aby_prng(a1, l);
+	aby_prng(b1, l);
+
+	gmp_printf("a0,b0: %Zd %Zd \n", a0, b0);
+	gmp_printf("a1,b1: %Zd %Zd \n", a1, b1);
+
+	// choose random r for masking
+	aby_prng(r, 2 * l + 2);
+
+	dgk_encrypt_plain(a0c, pub, a0); //encrypt a0
+	dgk_encrypt_plain(b0c, pub, b0); //encrypt b0
+	dgk_encrypt_plain(rc, pub, r); //encrypt r
+
+	mpz_mul(c1, a1, b1);
+	mpz_mod_2exp(c1, c1, l);
+	mpz_sub(c1, c1, r); // c1 = a1*b1 - r
+	mpz_mod_2exp(c1, c1, l); // % l (stay within plaintext space)
+
+	// homomorphic multiplication
+	mpz_powm(a0c, a0c, b1, pub->n);
+	mpz_powm(b0c, b0c, a1, pub->n);
+
+	// test from here
+	dgk_decrypt(d, pub, prv, a0c);
+	gmp_printf("---test shares---\ndec a0*b1= %Zd\n", d);
+
+	mpz_mul(tmp0, b1, a0);
+	gmp_printf("a0*b1=     %Zd\n", tmp0);
+
+	dgk_decrypt(d, pub, prv, b0c);
+	gmp_printf("dec a1*b0= %Zd\n", d);
+
+	mpz_mul(tmp1, b0, a1);
+	gmp_printf("a1*b0=     %Zd\n---test shares---\n", tmp1);
+	// test till here
+
+	mpz_mul(a0c, a0c, b0c); // multiply [a0]^b1 and [b0]^a1 (homomorphic addition)
+	mpz_mod(a0c, a0c, pub->n); // product % n (stay within ciphertext space)
+
+	// test from here
+	dgk_decrypt(d, pub, prv, a0c); // decrypt ciphertext (sum of products a0c, yet no r)
+	gmp_printf("dec 4x= %Zd\n", d);
+
+	mpz_add(tmp0, tmp0, tmp1); // add plaintext products, should be equal to d
+	gmp_printf("4x=     %Zd\n", tmp0);
+
+	mpz_add(tmp0, tmp0, r); // plaintext add r
+	mpz_mod_2exp(tmp1, tmp0, l); // mod l
+	gmp_printf("4x + r= %Zd = %Zd (mod l)\n", tmp0, tmp1);
+	// test till here
+
+	mpz_mul(a0c, a0c, rc); // homomorphic addition of r
+	mpz_mod(a0c, a0c, pub->n); // product % n
+
+	dgk_decrypt(d, pub, prv, a0c); // decrypt masked sum+r
+
+	mpz_mul(c0, a0, b0); // c0 = a0 * b0
+	mpz_mod_2exp(c0, c0, l); // c0 = c0 % 2^l
+	mpz_add(c0, c0, d); // c0 = c0 + d
+	mpz_mod_2exp(c0, c0, l); // c0 = c0 % 2^l
+
+	gmp_printf("%Zd %Zd %Zd\n", a0, b0, c0);
+	gmp_printf("%Zd %Zd %Zd\n", a1, b1, c1);
+	gmp_printf("%Zd %Zd\n", r, d);
+
+	// test if MT is valid: (a0+a1) * (b0+b1) = c0+c1  [mod l]
+	mpz_add(a0, a0, a1);
+	mpz_add(b0, b0, b1);
+	mpz_mul(a0, a0, b0);
+	mpz_add(c0, c0, c1);
+
+	mpz_mod_2exp(c0, c0, l);
+	mpz_mod_2exp(a0, a0, l);
+
+	if (mpz_cmp(a0, c0) == 0) {
+		printf("fine\n");
+	} else {
+		printf("ERR :(\n");
+	}
+}
+
+/**
+ * uncomment the following main for direct testing
+ * g++ dgk.cpp ../utils.cpp ../powmod.cpp -lgmp -O3 -g0 -o dgk
+ */
+// #include <time.h>
+// int main(){
+// 	srand (time(NULL)^clock());
+
+// 	// createKeys();
+// 	test_encdec();
+// 	test_sharing();
+// 	printf("DGK END.\n");
+
+// 	return 0;
+// }

+ 143 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/dgk.h

@@ -0,0 +1,143 @@
+/**
+ \file 		dgk.h
+ \author 	Daniel Demmler
+ \copyright Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+
+  This program 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 3 of the License, or
+  (at your option) any later version.
+  ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+
+ \brief		 libdgk - v0.9
+ A library implementing the DGK crypto system with full decryption
+ Thanks to Marina Blanton for sharing her Miracl DGK implementation from
+ M. Blanton and P. Gasti, "Secure and efficient protocols for iris and fingerprint identification" (ESORICS’11)
+ with us. We used it as a template for this GMP version.
+
+ The implementation structure was inspired by
+ libpailler - A library implementing the Paillier crypto system. (http://hms.isi.jhu.edu/acsc/libpaillier/)
+ */
+
+#ifndef _DGK_H_
+#define _DGK_H_
+#include <gmp.h>
+
+/*
+ This represents a DGK public key.
+ */
+struct dgk_pubkey_t {
+	unsigned int bits; /* key bits e.g., 1024 */
+	unsigned int lbits; /* share (message) length e.g., 32 */
+	mpz_t n; /* public modulus n = pq */
+	mpz_t u; /* u = 2^lbits (uses 2^(2lbits+2) internally) */
+	mpz_t g; /* generator g */
+	mpz_t h; /* generator h */
+};
+
+/*
+ This represents a DGK private key; it needs to be used with a
+ dgk_pubkey_t to be meaningful.
+ */
+struct dgk_prvkey_t {
+	mpz_t vp;
+	mpz_t vq;
+	mpz_t p;
+	mpz_t q;
+	mpz_t p_minusone;
+	mpz_t q_minusone;
+	mpz_t pinv;
+	mpz_t qinv;
+};
+
+extern mpz_t* powtwo;
+extern mpz_t* gvpvqp;
+
+/**
+ * create a DGK key pair. This will take some time, depending on the size (up to several minutes!)
+ * modulusbits is the size of the modulus n, e.g. 1024 or 2048 bit
+ * lbits is equal to the share length, e.g. 16 or 32 bit (We use 2*lbits+2 internally)
+ * the parameter t is internally fixed to 160, as recommended in the paper
+ * NOTE: this key generation is probabilistic and might create fauly keys!
+ *       Generated keys *MUST* be validated by running multiple trial encryption/decryptions and
+ *       checking the result for correctnes!
+ *       An example can be found in createKeys() in dgk.cpp:559
+ */
+void dgk_keygen(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, dgk_prvkey_t** prv);
+
+/**
+ * encrypt with public key only and double-base encryption - unfortunately not efficient due to different sized exponents, therefore deactivated
+ */
+//void dgk_encrypt_db(mpz_t res, dgk_pubkey_t* pub, mpz_t pt);
+/**
+ * encrypt with public key only, fixed-base encryption (must be initialized before first use!)
+ */
+void dgk_encrypt_fb(mpz_t res, dgk_pubkey_t* pub, mpz_t pt);
+
+/**
+ * encrypt with public key only, no further optimization (slower than fixed-base encryption)
+ */
+void dgk_encrypt_plain(mpz_t res, dgk_pubkey_t* pub, mpz_t pt);
+
+/**
+ * encrypt using CRT if we have the private key for efficiency
+ */
+void dgk_encrypt_crt(mpz_t res, dgk_pubkey_t* pub, dgk_prvkey_t* prv, mpz_t pt);
+
+/**
+ * use CRT and double base combined - unfortunately not efficient due to different sized exponents, therefore deactivated
+ */
+// void dgk_encrypt_crt_db(mpz_t res, dgk_pubkey_t* pub, dgk_prvkey_t* prv, mpz_t pt);
+/**
+ * DGK decryption
+ */
+void dgk_decrypt(mpz_t res, dgk_pubkey_t* pub, dgk_prvkey_t* prv, mpz_t ct);
+
+/**
+ * stores a generated key pair to disc
+ */
+void dgk_storekey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t* pub, dgk_prvkey_t* prv);
+
+/**
+ * reads a previously stored key pair from disc
+ */
+void dgk_readkey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, dgk_prvkey_t** prv);
+
+/*
+ These free the structures allocated and returned by various
+ functions within library and should be used when the structures are
+ no longer needed.
+ */
+void dgk_freepubkey(dgk_pubkey_t* pub);
+void dgk_freeprvkey(dgk_prvkey_t* prv);
+
+/**
+ * create the full public key struct type given only n, g and h (e.g. after key exchange)
+ */
+void dgk_complete_pubkey(unsigned int modulusbits, unsigned int lbits, dgk_pubkey_t** pub, mpz_t n, mpz_t g, mpz_t h);
+
+/**
+ * -------------------------------
+ * the following are internal functions, that should not be called from the outside unless you really know what they do, hence commented out
+ * -------------------------------
+ */
+
+/**
+ * create a batch of different keys and check that they are valid, overwrites existing keys (if any)
+ */
+// void createKeys(){
+/**
+ * test correct encrypt/decrypt
+ */
+//void test_encdec()
+
+/**
+ * test correct sharing
+ */
+//void test_sharing(){
+#endif

BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_16.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_32.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_64.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_1024_8.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_16.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_32.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_64.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_2048_8.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_16.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_32.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_64.bin


BIN
2p-preprocessing/ENCRYPTO_utils/crypto/dgk_key_3072_8.bin


+ 357 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/djn.cpp

@@ -0,0 +1,357 @@
+/**
+ \file 		djn.cpp
+ \author 	Daniel Demmler
+ \copyright Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief
+ libdjn - v0.9
+ A library implementing the Damgaard Jurik Nielsen cryptosystem with s=1 (~Paillier).
+ based on:
+ libpaillier - A library implementing the Paillier cryptosystem.
+ (http://hms.isi.jhu.edu/acsc/libpaillier/)
+ */
+
+#include "djn.h"
+#include "../powmod.h"
+#include "../utils.h"
+#include <cstdlib>
+
+#define DJN_DEBUG 0
+#define DJN_CHECKSIZE 0
+
+void djn_complete_pubkey(unsigned int modulusbits, djn_pubkey_t** pub, mpz_t n, mpz_t h) {
+	*pub = (djn_pubkey_t*) malloc(sizeof(djn_pubkey_t));
+
+	/* initialize our integers */
+	mpz_init((*pub)->n);
+	mpz_init((*pub)->n_squared);
+	mpz_init((*pub)->h);
+	mpz_init((*pub)->h_s);
+
+	mpz_set((*pub)->n, n);
+	mpz_set((*pub)->h, h);
+	mpz_mul((*pub)->n_squared, n, n);
+	mpz_powm((*pub)->h_s, h, n, (*pub)->n_squared);
+	(*pub)->bits = modulusbits;
+	(*pub)->rbits = modulusbits % 2 ? modulusbits / 2 + 1 : modulusbits / 2; // rbits = ceil(bits/2)
+
+}
+
+void djn_keygen(unsigned int modulusbits, djn_pubkey_t** pub, djn_prvkey_t** prv) {
+	mpz_t test, x;
+
+	/* allocate the new key structures */
+	*pub = (djn_pubkey_t*) malloc(sizeof(djn_pubkey_t));
+	*prv = (djn_prvkey_t*) malloc(sizeof(djn_prvkey_t));
+
+	/* initialize our integers */
+	mpz_init((*pub)->n);
+	mpz_init((*pub)->n_squared);
+	mpz_init((*pub)->h);
+	mpz_init((*pub)->h_s);
+
+	mpz_init((*prv)->lambda);
+	mpz_init((*prv)->lambda_inverse);
+	mpz_init((*prv)->p);
+	mpz_init((*prv)->q);
+	mpz_init((*prv)->p_squared);
+	mpz_init((*prv)->q_squared);
+	mpz_init((*prv)->q_inverse);
+	mpz_init((*prv)->q_squared_inverse);
+	mpz_init((*prv)->p_minusone);
+	mpz_init((*prv)->q_minusone);
+	mpz_init((*prv)->ordpsq);
+	mpz_init((*prv)->ordqsq);
+	mpz_init(test);
+	mpz_init(x);
+
+	do {
+		// choose bits of p and q randomly
+		aby_prng((*prv)->p, modulusbits / 2);
+		aby_prng((*prv)->q, modulusbits / 2);
+
+		// set highest bit to 1 to ensure high length
+		mpz_setbit((*prv)->p, modulusbits / 2);
+		mpz_setbit((*prv)->q, modulusbits / 2);
+
+		//find next primes
+		do {
+			mpz_nextprime((*prv)->p, (*prv)->p);
+		} while (!mpz_tstbit((*prv)->p, 1)); //make sure p mod 4 = 3
+
+		do {
+			mpz_nextprime((*prv)->q, (*prv)->q);
+		} while (!mpz_cmp((*prv)->p, (*prv)->q) || !mpz_tstbit((*prv)->q, 1)); //make sure p!=q and q mod 4 = 3
+
+		/* p-1 and q-1 */
+		mpz_sub_ui((*prv)->p_minusone, (*prv)->p, 1);
+		mpz_sub_ui((*prv)->q_minusone, (*prv)->q, 1);
+
+		mpz_gcd(test, (*prv)->p_minusone, (*prv)->q_minusone);
+
+	} while (mpz_cmp_ui(test, 2)); // make sure gcd(p-1,q-1)=2
+
+	//} while((mpz_cmp_ui(test,2) || !mpz_tstbit((*pub)->n, modulusbits - 1) ); // make sure gcd(p-1,q-1)=2 and first bit of n is set
+
+	//complete_pubkey(*pub);
+
+	/* compute the public modulus n = p q */
+	mpz_mul((*pub)->n, (*prv)->p, (*prv)->q);
+	mpz_mul((*pub)->n_squared, (*pub)->n, (*pub)->n);
+
+#if DJN_DEBUG
+	if (!mpz_tstbit((*pub)->n, modulusbits - 1)) {
+		printf("DJN n too small!?\n");
+	}
+#endif
+
+	/* p^2 and q^2 */
+	mpz_mul((*prv)->p_squared, (*prv)->p, (*prv)->p);
+	mpz_mul((*prv)->q_squared, (*prv)->q, (*prv)->q);
+	mpz_sub((*prv)->ordpsq, (*prv)->p_squared, (*prv)->p);
+	mpz_sub((*prv)->ordqsq, (*prv)->q_squared, (*prv)->q);
+
+	/* computer multiplicative inverse of q mod p and q^2 mod p^2 for CRT*/
+	mpz_invert((*prv)->q_inverse, (*prv)->q, (*prv)->p);
+	mpz_invert((*prv)->q_squared_inverse, (*prv)->q_squared, (*prv)->p_squared);
+
+	/* save one multiplication for CRT */
+	mpz_mul((*prv)->q_squared_inverse, (*prv)->q_squared_inverse, (*prv)->q_squared);
+	mpz_mul((*prv)->q_inverse, (*prv)->q_inverse, (*prv)->q);
+
+#if DJN_DEBUG
+	gmp_printf("p = %Zd\nq = %Zd\nn = %Zd\nn^2 = %Zd\n", (*prv)->p, (*prv)->q, (*pub)->n, (*pub)->n_squared);
+#endif
+
+	/* pick random x in Z_n^* */
+	do {
+		aby_prng(x, mpz_sizeinbase((*pub)->n, 2) + 128);
+		mpz_mod(x, x, (*pub)->n);
+		mpz_gcd(test, x, (*pub)->n);
+	} while (mpz_cmp_ui(test, 1));
+
+//	gmp_printf("x = %Zd\n", x);
+
+	mpz_mul(x, x, x);
+//	gmp_printf("x^2 = %Zd\n", x);
+	mpz_neg(x, x);
+//	gmp_printf("-x^2 = %Zd\n", x);
+	mpz_mod((*pub)->h, x, (*pub)->n);
+//	mpz_powm((*pub)->h_s, (*pub)->h, (*pub)->n, (*pub)->n_squared);
+	djn_pow_mod_n_squared_crt((*pub)->h_s, (*pub)->h, (*pub)->n, *pub, *prv);
+
+	(*pub)->bits = modulusbits;
+	(*pub)->rbits = modulusbits % 2 ? modulusbits / 2 + 1 : modulusbits / 2; // rbits = ceil(bits/2)
+
+	/* compute the private key lambda = lcm(p-1,q-1) = (p-1)(q-1)/2 */
+	//mpz_lcm((*prv)->lambda, (*prv)->p_minusone, (*prv)->q_minusone);
+	mpz_mul((*prv)->lambda, (*prv)->p_minusone, (*prv)->q_minusone);
+	mpz_fdiv_q_2exp((*prv)->lambda, (*prv)->lambda, 1); // division by two
+
+	/* compute multiplicative inverse of lambda */
+	mpz_invert((*prv)->lambda_inverse, (*prv)->lambda, (*pub)->n);
+
+#if DJN_DEBUG
+	gmp_printf("h = %Zd\nh_s = %Zd\n", (*pub)->h, (*pub)->h_s);
+	printf("rbits = %d, bits = %d\n", (*pub)->rbits, (*pub)->bits);
+	gmp_printf("lambda = %Zd\nlambda_inverse = %Zd\n", (*prv)->lambda, (*prv)->lambda_inverse);
+#endif
+
+	/* clear temporary integers */
+	mpz_clears(x, test, NULL);
+}
+
+/**
+ * encrypt plaintext to res
+ */
+void djn_encrypt(mpz_t res, djn_pubkey_t* pub, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DJN_CHECKSIZE
+	if (mpz_cmp(plaintext, pub->n) >= 0) {
+		printf("WARNING: m>=N!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, pub->rbits);
+
+#if DJN_DEBUG
+	gmp_printf("r = %Zd\n", r);
+#endif
+
+	mpz_mul(res, plaintext, pub->n);
+	mpz_add_ui(res, res, 1);
+	mpz_mod(res, res, pub->n_squared);
+
+	mpz_powm(r, pub->h_s, r, pub->n_squared);
+
+	mpz_mul(res, res, r);
+	mpz_mod(res, res, pub->n_squared);
+
+	mpz_clear(r);
+}
+
+/**
+ * encrypt plaintext using crt if private key is known
+ */
+void djn_encrypt_crt(mpz_t res, djn_pubkey_t* pub, djn_prvkey_t* prv, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DJN_CHECKSIZE
+	if (mpz_cmp(plaintext, pub->n) >= 0) {
+		printf("WARNING: m>=N!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, pub->rbits);
+
+#if DJN_DEBUG
+	gmp_printf("r = %Zd\n", r);
+#endif
+
+	mpz_mul(res, plaintext, pub->n);
+	mpz_add_ui(res, res, 1);
+	mpz_mod(res, res, pub->n_squared);
+
+	djn_pow_mod_n_squared_crt(r, pub->h_s, r, pub, prv);
+
+	mpz_mul(res, res, r);
+	mpz_mod(res, res, pub->n_squared);
+
+	mpz_clear(r);
+}
+
+/**
+ * mpz_t version of encrypt_crt
+ */
+void djn_encrypt_fb(mpz_t res, djn_pubkey_t* pub, mpz_t plaintext) {
+	mpz_t r;
+	mpz_init(r);
+
+#if DJN_CHECKSIZE
+	if (mpz_cmp(plaintext, pub->n) >= 0) {
+		printf("WARNING: m>=N!\n");
+	}
+#endif
+
+	/* pick random blinding factor r */
+	aby_prng(r, pub->rbits);
+
+#if DJN_DEBUG
+	gmp_printf("r = %Zd\n", r);
+#endif
+
+	mpz_mul(res, plaintext, pub->n);
+	mpz_add_ui(res, res, 1);
+	mpz_mod(res, res, pub->n_squared);
+
+	// r = h_s ^ r
+	fbpowmod_g(r, r);
+
+	mpz_mul(res, res, r);
+	mpz_mod(res, res, pub->n_squared);
+
+	mpz_clear(r);
+}
+
+/**
+ * decrypt, using CRT, assumes res to be initialized
+ */
+void djn_decrypt(mpz_t res, djn_pubkey_t* pub, djn_prvkey_t* prv, mpz_t ciphertext) {
+	/* powmod using CRT */
+	djn_pow_mod_n_squared_crt(res, ciphertext, prv->lambda, pub, prv);
+
+	mpz_sub_ui(res, res, 1);
+	mpz_divexact(res, res, pub->n);
+	mpz_mul(res, res, prv->lambda_inverse);
+	mpz_mod(res, res, pub->n);
+}
+
+/**
+ * plain decrypt version without crt (= much slower), assumes res to be initialized
+ */
+void djn_decrypt_plain(mpz_t res, djn_pubkey_t* pub, djn_prvkey_t* prv, mpz_t ciphertext) {
+	mpz_powm(res, ciphertext, prv->lambda, pub->n_squared);
+
+	mpz_sub_ui(res, res, 1);
+	mpz_divexact(res, res, pub->n);
+	mpz_mul(res, res, prv->lambda_inverse);
+	mpz_mod(res, res, pub->n);
+}
+
+void djn_freepubkey(djn_pubkey_t* pub) {
+	mpz_clear(pub->n);
+	mpz_clear(pub->h);
+	mpz_clear(pub->n_squared);
+	mpz_clear(pub->h_s);
+	free(pub);
+}
+
+void djn_freeprvkey(djn_prvkey_t* prv) {
+	mpz_clears(prv->lambda, prv->lambda_inverse, prv->ordpsq, prv->ordqsq, prv->p, prv->p_minusone, prv->p_squared, prv->q,
+			prv->q_minusone, prv->q_squared, prv->q_inverse, prv->q_squared_inverse,
+			NULL);
+
+	free(prv);
+}
+
+/* calculate base^exp mod n using fermats little theorem and CRT */
+void djn_pow_mod_n_crt(mpz_t res, const mpz_t base, const mpz_t exp, const djn_pubkey_t* pub, const djn_prvkey_t* prv) {
+	mpz_t temp, cp, cq;
+	mpz_inits(cp, cq, temp, NULL);
+
+	/* smaller exponents due to fermat: e mod (p-1), e mod (q-1) */
+	mpz_mod(cp, exp, prv->p_minusone);
+	mpz_mod(cq, exp, prv->q_minusone);
+
+	/* smaller exponentiations of base mod p, q */
+	mpz_mod(temp, base, prv->p);
+	mpz_powm(cp, temp, cp, prv->p);
+
+	mpz_mod(temp, base, prv->q);
+	mpz_powm(cq, temp, cq, prv->q);
+
+	/* CRT to calculate base^exp mod (pq) */
+	mpz_sub(cp, cp, cq);
+	mpz_addmul(cq, cp, prv->q_inverse);
+	mpz_mod(res, cq, pub->n);
+
+	mpz_clears(cp, cq, temp, NULL);
+}
+
+/* calculate base^exp mod n^2 using fermats little theorem and CRT */
+void djn_pow_mod_n_squared_crt(mpz_t res, const mpz_t base, const mpz_t exp, const djn_pubkey_t* pub, const djn_prvkey_t* prv) {
+	mpz_t temp, cp, cq;
+	mpz_inits(cp, cq, temp, NULL);
+
+	/* smaller exponents due to fermat: e mod (p-1), e mod (q-1) */
+	mpz_mod(cp, exp, prv->ordpsq);
+	mpz_mod(cq, exp, prv->ordqsq);
+
+	/* smaller exponentiations of base mod p^2, q^2 */
+	mpz_mod(temp, base, prv->p_squared);
+	mpz_powm(cp, temp, cp, prv->p_squared);
+
+	mpz_mod(temp, base, prv->q_squared);
+	mpz_powm(cq, temp, cq, prv->q_squared);
+
+	/* CRT to calculate base^exp mod n^2 */
+	mpz_sub(cp, cp, cq);
+	mpz_addmul(cq, cp, prv->q_squared_inverse);
+	mpz_mod(res, cq, pub->n_squared);
+
+	mpz_clears(cp, cq, temp, NULL);
+}

+ 176 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/djn.h

@@ -0,0 +1,176 @@
+/**
+ \file 		djn.h
+ \author 	Daniel Demmler
+ \copyright Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+
+ \brief
+ libdjn - v0.9
+ A library implementing the Damgaard Jurik Nielsen cryptosystem with s=1 (~Paillier).
+ based on:
+ libpaillier - A library implementing the Paillier cryptosystem.
+ (http://hms.isi.jhu.edu/acsc/libpaillier/)
+ */
+
+#ifndef _DJN_H_
+#define _DJN_H_
+#include <gmp.h>
+
+/*
+ On memory handling:
+
+ At no point is any special effort made to securely "shred" sensitive
+ memory or prevent it from being paged out to disk. This means that
+ it is important that functions dealing with private keys and
+ plaintexts (e.g., djn_keygen and djn_enc) only be run on
+ trusted machines. The resulting ciphertexts and public keys,
+ however, may of course be handled in an untrusted manner.
+
+ */
+
+/******
+ TYPES
+ *******/
+
+/*
+ This represents a public key, which is the modulus n plus a generator h.
+ */
+struct djn_pubkey_t {
+	int bits; /* e.g., 1024 */
+	int rbits; /* e.g., 512 */
+	mpz_t n; /* public modulus n = p q */
+	mpz_t n_squared; /* cached to avoid recomputing */
+	mpz_t h; /* generator h = -x^2 mod n */
+	mpz_t h_s; /* h_s = h^n mod n^2 */
+};
+
+/*
+ This represents a Paillier private key; it needs to be used with a
+ djn_pubkey_t to be meaningful. It includes the Carmichael
+ function (lambda) of the modulus. The other value is kept for
+ efficiency and should be considered private.
+ */
+struct djn_prvkey_t {
+	mpz_t lambda; /* lambda(n), i.e., lcm(p-1,q-1) */
+	mpz_t lambda_inverse; /* inverse of lambda (mod n)*/
+	mpz_t p; /* cached to avoid recomputing */
+	mpz_t q; /* cached to avoid recomputing */
+	mpz_t q_inverse; /* inverse of q (mod p) */
+	mpz_t q_squared_inverse; /* inverse of q^2 (mod p^2) */
+	mpz_t p_minusone; /* cached to avoid recomputing */
+	mpz_t q_minusone; /* cached to avoid recomputing */
+	mpz_t p_squared; /* cached to avoid recomputing */
+	mpz_t q_squared; /* cached to avoid recomputing */
+	mpz_t ordpsq; /* p^2-p */
+	mpz_t ordqsq; /* q^2-q */
+};
+
+/*
+ This is the type of the callback functions used to obtain the
+ randomness needed by the probabilistic algorithms. The functions
+ djn_get_rand_devrandom and djn_get_rand_devurandom
+ (documented later) may be passed to any library function requiring a
+ djn_get_rand_t, or you may implement your own. If you implement
+ your own such function, it should fill in "len" random bytes in the
+ array "buf".
+ */
+typedef void (*djn_get_rand_t)(void* buf, int len);
+
+/*****************
+ BASIC OPERATIONS
+ *****************/
+
+/*
+ Generate a keypair of length modulusbits using randomness from the
+ provided get_rand function. Space will be allocated for each of the
+ keys, and the given pointers will be set to point to the new
+ djn_pubkey_t and djn_prvkey_t structures. The functions
+ djn_get_rand_devrandom and djn_get_rand_devurandom may be
+ passed as the final argument.
+ */
+void djn_keygen(unsigned int modulusbits, djn_pubkey_t** pub, djn_prvkey_t** prv);
+
+/*
+ Encrypt the given plaintext with the given public key using
+ randomness from get_rand for blinding. If res is not null, its
+ contents will be overwritten with the result. Otherwise, a new
+ djn_ciphertext_t will be allocated and returned.
+ */
+void djn_encrypt(mpz_t res, djn_pubkey_t* pub, mpz_t pt);
+
+/*
+ Encrypt the given plaintext with the given public key using
+ randomness from get_rand for blinding. If res is not null, its
+ contents will be overwritten with the result. Otherwise, a new
+ djn_ciphertext_t will be allocated and returned.
+ */
+void djn_encrypt_crt(mpz_t res, djn_pubkey_t* pub, djn_prvkey_t* prv, mpz_t pt);
+
+/**
+ * fixed base encryption. Requires pre-computed fixed base table.
+ */
+void djn_encrypt_fb(mpz_t res, djn_pubkey_t* pub, mpz_t plaintext);
+
+/*
+ Decrypt the given ciphertext with the given key pair. If res is not
+ null, its contents will be overwritten with the result. Otherwise, a
+ new djn_plaintext_t will be allocated and returned.
+ */
+void djn_decrypt(mpz_t res, djn_pubkey_t* pub, djn_prvkey_t* prv, mpz_t ct);
+
+/**********************
+ KEY IMPORT AND EXPORT
+ **********************/
+
+/*
+ Import or export public and private keys from or to hexadecimal,
+ ASCII strings, which are suitable for I/O. Note that the
+ corresponding public key is necessary to initialize a private key
+ from a hex string. In all cases, the returned value is allocated for
+ the caller and the values passed are unchanged.
+ */
+char* djn_pubkey_to_hex(djn_pubkey_t* pub);
+char* djn_prvkey_to_hex(djn_prvkey_t* prv);
+djn_pubkey_t* djn_pubkey_from_hex(char* str);
+djn_prvkey_t* djn_prvkey_from_hex(char* str, djn_pubkey_t* pub);
+
+/********
+ CLEANUP
+ ********/
+
+/*
+ These free the structures allocated and returned by various
+ functions within library and should be used when the structures are
+ no longer needed.
+ */
+void djn_freepubkey(djn_pubkey_t* pub);
+void djn_freeprvkey(djn_prvkey_t* prv);
+
+/***********
+ MISC STUFF
+ ***********/
+
+/*
+ Just a utility used internally when we need round a number of bits
+ up the number of bytes necessary to hold them.
+ */
+#define PAILLIER_BITS_TO_BYTES(n) ((n) % 8 ? (n) / 8 + 1 : (n) / 8)
+
+void djn_pow_mod_n_crt(mpz_t res, const mpz_t b, const mpz_t e, const djn_pubkey_t* pub, const djn_prvkey_t* prv);
+void djn_pow_mod_n_squared_crt(mpz_t res, const mpz_t b, const mpz_t e, const djn_pubkey_t* pub, const djn_prvkey_t* prv);
+
+/**
+ * create full public key given only n and h (e.g., after a key exchange)
+ */
+void djn_complete_pubkey(unsigned int modulusbits, djn_pubkey_t** pub, mpz_t n, mpz_t h);
+
+#endif

+ 442 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/ecc-pk-crypto.cpp

@@ -0,0 +1,442 @@
+/**
+ \file 		ecc-pk-crypto.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ecc-pk-crypto.h"
+
+
+void ecc_field::init(seclvl sp, uint8_t* seed) {
+	relic_mutex.lock();
+	core_set(NULL);
+	
+	core_init(); //initialize the relic library
+	rand_seed(seed, sp.symbits >> 3); //set the seed of the relic's internal random generator
+	eb_param_set_any_plain();
+
+	fe_bytelen = ceil_divide(ECCLVL, 8) + 1;
+
+	context = core_get();
+	relic_mutex.unlock();
+
+	generator = (ecc_fe*) get_generator();
+	order = get_order();
+}
+
+ecc_field::~ecc_field() {
+	delete generator;
+	delete order;
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+	core_clean();
+}
+
+num* ecc_field::get_num() {
+	return new ecc_num(this);
+}
+
+num* ecc_field::get_order() {
+	relic_mutex.lock();
+	core_set(context);
+
+	bn_t bn_order;
+	bn_null(bn_order);
+	bn_new(bn_order);
+	eb_curve_get_ord(bn_order);
+
+	relic_mutex.unlock();
+	return new ecc_num(this, bn_order);
+}
+
+num* ecc_field::get_rnd_num(uint32_t bitlen) {
+	if (bitlen == 0) {
+		bitlen = ECCLVL;
+	}
+
+	relic_mutex.lock();
+	core_set(context);
+
+	bn_t rnd;
+	bn_null(rnd);
+	bn_new(rnd);
+
+	bn_rand(rnd, RLC_POS, bitlen);
+
+	relic_mutex.unlock();
+
+	num* res = new ecc_num(this, rnd);
+	return res;
+}
+fe* ecc_field::get_fe() {
+	return new ecc_fe(this);
+}
+
+fe* ecc_field::get_rnd_fe() {
+	return sample_random_point();
+}
+
+fe* ecc_field::get_generator() {
+	relic_mutex.lock();
+	core_set(context);
+
+	eb_t eb_generator;
+	eb_null(eb_generator);
+	eb_new(eb_generator);
+	eb_curve_get_gen(eb_generator);
+
+	relic_mutex.unlock();
+
+	return new ecc_fe(this, eb_generator);
+}
+fe* ecc_field::get_rnd_generator() {
+	//TODO not sure how this method is supposed to work
+	return sample_random_point();
+}
+uint32_t ecc_field::num_byte_size() {
+		return ceil_divide(ECCLVL, 8);
+	}
+uint32_t ecc_field::get_field_size() {
+	return ECCLVL;
+}
+brickexp* ecc_field::get_brick(fe* gen) {
+	return new ecc_brickexp(gen, this);
+}
+uint32_t ecc_field::get_size() {
+	return ECCLVL;
+}
+
+fe* ecc_field::sample_random_point() {
+	relic_mutex.lock();
+	core_set(context);
+
+	eb_t tmp_eb;
+	eb_null(tmp_eb);
+	eb_new(tmp_eb);
+	eb_rand(tmp_eb);
+
+	relic_mutex.unlock();
+
+	fe* tmp_fe = new ecc_fe(this, tmp_eb);
+	return tmp_fe;
+}
+
+ctx_t* ecc_field::get_context() {
+	return context;
+}
+
+ecc_fe::ecc_fe(ecc_field* fld) {
+	field = fld;
+	init();
+}
+
+ecc_fe::ecc_fe(ecc_field* fld, eb_t src) {
+	field = fld;
+	init();
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_copy(val, src);
+}
+ecc_fe::~ecc_fe() {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_free(val);
+}
+
+void ecc_fe::set(fe* src) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t tmp_val;
+	((ecc_fe*) src)->get_val(tmp_val);
+	eb_copy(val, tmp_val);
+}
+
+void ecc_fe::get_val(eb_t res) {
+	shallow_copy(res, val);
+}
+
+//Note: if the same value is processed, a has to be this value
+void ecc_fe::set_mul(fe* a, fe* b) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t eb_a;
+	eb_t eb_b;
+	((ecc_fe*) a)->get_val(eb_a);
+	((ecc_fe*) b)->get_val(eb_b);
+
+	eb_add(val, eb_a, eb_b);
+}
+
+void ecc_fe::set_pow(fe* a, num* e) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t eb_a;
+	bn_t bn_e;
+	((ecc_fe*) a)->get_val(eb_a);
+	((ecc_num*) e)->get_val(bn_e);
+
+	eb_mul(val, eb_a, bn_e);
+}
+
+//Note: if the same value is processed, a has to be this value
+void ecc_fe::set_div(fe* a, fe* b) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t eb_a;
+	eb_t eb_b;
+	((ecc_fe*) a)->get_val(eb_a);
+	((ecc_fe*) b)->get_val(eb_b);
+
+	eb_sub(val, eb_a, eb_b);
+}
+
+//TODO not sure what double here means, please check
+void ecc_fe::set_double_pow_mul(fe* b1, num* e1, fe* b2, num* e2) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t eb_b1;
+	eb_t eb_b2;
+	((ecc_fe*) b1)->get_val(eb_b1);
+	((ecc_fe*) b2)->get_val(eb_b2);
+	bn_t bn_e1;
+	bn_t bn_e2;
+	((ecc_num*) e1)->get_val(bn_e1);
+	((ecc_num*) e2)->get_val(bn_e2);
+
+	eb_mul_sim(val, eb_b1, bn_e1, eb_b2, bn_e2);
+}
+
+void ecc_fe::import_from_bytes(uint8_t* buf) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_read_bin(val, buf, field->fe_byte_size());
+}
+
+void ecc_fe::export_to_bytes(uint8_t* buf) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_write_bin(buf, field->fe_byte_size(), val, true);
+}
+
+//TODO not sure what the difference to import_from_bytes is yet
+void ecc_fe::sample_fe_from_bytes(uint8_t* buf, uint32_t bytelen) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_read_bin(val, buf, bytelen);
+	//TODO normalizing or something like that
+}
+bool ecc_fe::eq(fe* a) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t to_cmp;
+	((ecc_fe*) a)->get_val(to_cmp);
+	return eb_cmp(val, to_cmp) == RLC_EQ;
+}
+
+void ecc_fe::init() {
+	context = field->get_context();
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_null(val);
+	eb_new(val);
+};
+void ecc_fe::print() {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_print(val);
+};
+
+void ecc_fe::shallow_copy(eb_t to, eb_t from) {
+	*to = *from;
+}
+
+ecc_num::ecc_num(ecc_field* fld) {
+	field = fld;
+	context = field->get_context();
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_null(val);
+	bn_new(val);
+}
+ecc_num::ecc_num(ecc_field* fld, bn_t src) {
+	field = fld;
+	context = field->get_context();
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_null(val);
+	bn_new(val);
+	bn_copy(val, src);
+}
+
+ecc_num::~ecc_num() {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_free(val);
+}
+
+void ecc_num::get_val(bn_t res) {
+	shallow_copy(res, val);
+}
+
+void ecc_num::set(num* src) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_t tmp_val;
+	((ecc_num*) src)->get_val(tmp_val);
+	bn_copy(val, tmp_val);
+}
+void ecc_num::set_si(int32_t src) {
+	//TODO implement this method
+}
+void ecc_num::set_add(num* a, num* b) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_t bn_a;
+	bn_t bn_b;
+	((ecc_num*) a)->get_val(bn_a);
+	((ecc_num*) b)->get_val(bn_b);
+	bn_add(val, bn_a, bn_b);
+}
+void ecc_num::set_sub(num* a, num* b) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_t bn_a;
+	bn_t bn_b;
+	((ecc_num*) a)->get_val(bn_a);
+	((ecc_num*) b)->get_val(bn_b);
+	bn_sub(val, bn_a, bn_b);
+}
+void ecc_num::set_mul(num* a, num* b) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_t bn_a;
+	bn_t bn_b;
+	((ecc_num*) a)->get_val(bn_a);
+	((ecc_num*) b)->get_val(bn_b);
+	bn_mul(val, bn_a, bn_b);
+}
+
+void ecc_num::mod(num* modulus) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_t bn_mod;
+	((ecc_num*) modulus)->get_val(bn_mod);
+	bn_mod(val, val, bn_mod);
+}
+
+void ecc_num::set_mul_mod(num* a, num* b, num* modulus) {
+	//TODO is normalizing meant instead?
+	set_mul(a, b);
+	mod(modulus);
+}
+
+void ecc_num::import_from_bytes(uint8_t* buf, uint32_t field_size_bytes) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_read_bin(val, buf, field_size_bytes);
+}
+
+//export and pad all leading zeros
+void ecc_num::export_to_bytes(uint8_t* buf, uint32_t field_size_bytes) {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_write_bin(buf, field_size_bytes, val);
+}
+
+void ecc_num::print() {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	bn_print(val);
+};
+
+void ecc_num::shallow_copy(bn_t to, bn_t from) {
+	*to = *from;
+}
+
+ecc_brickexp::ecc_brickexp(fe* generator, ecc_field* field) {
+	this->field = field;
+	context = field->get_context();
+
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	eb_t tmp_val;
+	((ecc_fe*) generator)->get_val(tmp_val);
+	eb_table = new eb_t[RLC_EB_TABLE_MAX];
+	for(uint32_t i = 0; i < RLC_EB_TABLE_MAX; i++) {
+		eb_null(eb_table[i]);
+	}
+	for(uint32_t i = 0; i < RLC_EB_TABLE; i++) {
+		eb_new(eb_table[i]);
+	}
+	eb_mul_pre(eb_table, tmp_val);
+}
+
+ecc_brickexp::~ecc_brickexp() {
+	std::lock_guard<std::mutex> lock(relic_mutex);
+	core_set(context);
+
+	for(uint32_t i = 0; i < RLC_EB_TABLE; ++i) {
+		eb_free(eb_table[i]);
+	}
+	delete eb_table;
+}
+
+
+void ecc_brickexp::pow(fe* result, num* e) {
+	relic_mutex.lock();
+	core_set(context);
+
+	eb_t eb_res;
+	eb_null(eb_res);
+	eb_new(eb_res);
+	bn_t bn_e;
+	((ecc_num*) e)->get_val(bn_e);
+	eb_mul_fix(eb_res, eb_table, bn_e);
+
+	relic_mutex.unlock();
+
+	ecc_fe tmp_fe(field, eb_res);
+	result->set(&tmp_fe);
+
+}

+ 141 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/ecc-pk-crypto.h

@@ -0,0 +1,141 @@
+/**
+ \file 		ecc-pk-crypto.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Class with ECC operations
+ */
+
+#ifndef ECC_PK_CRYPTO_H_
+#define ECC_PK_CRYPTO_H_
+
+#include "pk-crypto.h"
+
+extern "C"
+{
+	#include <relic.h>
+}
+
+#include <memory>
+#include <vector>
+#include <mutex>
+
+class ecc_num;
+class ecc_fe;
+class ecc_brickexp;
+
+static std::mutex relic_mutex;
+
+class ecc_field: public pk_crypto {
+public:
+	ecc_field(seclvl sp, uint8_t* seed) :
+			pk_crypto(sp) {
+		init(sp, seed);
+	};
+	~ecc_field();
+
+	num* get_num();
+	num* get_rnd_num(uint32_t bitlen = 0);
+	fe* get_fe();
+	fe* get_rnd_fe();
+	fe* get_generator();
+	fe* get_rnd_generator();
+	uint32_t get_size();
+	//fe* sample_fe_from_bytes(uint8_t* buf, uint32_t bytelen);
+	num* get_order();
+	uint32_t num_byte_size();
+	uint32_t get_field_size();
+
+	brickexp* get_brick(fe* gen);
+
+	ctx_t* get_context();
+
+protected:
+	void init(seclvl sp, uint8_t* seed);
+private:
+	fe* sample_random_point();
+	ecc_fe* generator;
+	ctx_t* context;
+};
+
+class ecc_num: public num {
+
+public:
+	ecc_num(ecc_field* fld);
+	ecc_num(ecc_field* fld, bn_t src);
+	~ecc_num();
+	void set(num* src);
+	void set_si(int32_t src);
+	void set_add(num* a, num* b);
+	void set_sub(num* a, num* b);
+	void set_mul(num* a, num* b);
+	void mod(num* mod);
+	void set_mul_mod(num* a, num* b, num* modulus) ;
+
+	void get_val(bn_t res);
+
+	void export_to_bytes(uint8_t* buf, uint32_t field_size_bytes);
+	void import_from_bytes(uint8_t* buf, uint32_t field_size_bytes);
+	//void set_rnd(uint32_t bits); Seems useless since not implemented
+	void print();
+
+private:
+	void shallow_copy(bn_t to, bn_t from);
+
+	bn_t val;
+	ecc_field* field;
+	ctx_t* context;
+};
+
+class ecc_fe: public fe {
+public:
+	ecc_fe(ecc_field* fld);
+	ecc_fe(ecc_field* fld, eb_t src);
+	~ecc_fe();
+	void set(fe* src);
+	void get_val(eb_t res);
+	void set_mul(fe* a, fe* b);
+
+	void set_pow(fe* b, num* e);
+	void set_div(fe* a, fe* b);
+	void set_double_pow_mul(fe* b1, num* e1, fe* b2, num* e2);
+	void export_to_bytes(uint8_t* buf);
+	void import_from_bytes(uint8_t* buf);
+	void sample_fe_from_bytes(uint8_t* buf, uint32_t bytelen);
+	bool eq(fe* a);
+
+	void print();
+
+private:
+	void init();
+	void shallow_copy(eb_t to, eb_t from);
+	eb_t val;
+	ecc_field* field;
+	ctx_t* context;
+};
+
+class ecc_brickexp: public brickexp {
+public:
+	ecc_brickexp(fe* generator, ecc_field* field);
+	~ecc_brickexp();
+
+	void pow(fe* res, num* e);
+private:
+	uint32_t eb_pre_size;
+	eb_t* eb_table;
+	ecc_field* field;
+	ctx_t* context;
+};
+
+
+#endif /* ECC_PK_CRYPTO_H_ */

File diff suppressed because it is too large
+ 35 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/gmp-pk-crypto.cpp


+ 143 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/gmp-pk-crypto.h

@@ -0,0 +1,143 @@
+/**
+ \file 		gmp-pk-crypto.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Class with finite-field-cryptography operations (using the GMP library)
+ */
+
+#ifndef GMP_PK_CRYPTO_H_
+#define GMP_PK_CRYPTO_H_
+
+#include "pk-crypto.h"
+#include "../utils.h"
+#include <gmp.h>
+
+class prime_field;
+class gmp_fe;
+class gmp_num;
+class gmp_brickexp;
+
+#define fe2mpz(fieldele) (((gmp_fe*) (fieldele))->get_val())
+#define num2mpz(number) (((gmp_num*) (number))->get_val())
+
+class prime_field: public pk_crypto {
+public:
+	prime_field(seclvl sp, uint8_t* seed) :
+			pk_crypto(sp) {
+		init(sp, seed);
+	}
+	;
+	~prime_field();
+
+	num* get_num();
+	num* get_rnd_num(uint32_t bitlen = 0);
+	fe* get_fe();
+	fe* get_rnd_fe();
+	fe* get_generator();
+	fe* get_rnd_generator();
+	num* get_order();
+
+	mpz_t* get_p();
+	uint32_t get_size();
+	brickexp* get_brick(fe* gen);
+
+	uint32_t num_byte_size() {
+		return ceil_divide(secparam.ifcbits, 8);
+	}
+	uint32_t get_field_size() {
+		return secparam.ifcbits;
+	}
+	;
+
+protected:
+	void init(seclvl sp, uint8_t* seed);
+private:
+	mpz_t p;
+	mpz_t g;
+	mpz_t q;
+};
+
+class gmp_fe: public fe {
+public:
+	gmp_fe(prime_field* fld);
+	gmp_fe(prime_field* fld, mpz_t src);
+	~gmp_fe();
+	void set(fe* src);
+	mpz_t* get_val();
+
+	void set_mul(fe* a, fe* b);
+	void set_pow(fe* b, num* e);
+	void set_div(fe* a, fe* b);
+	void set_double_pow_mul(fe* b1, num* e1, fe* b2, num* e2);
+	void export_to_bytes(uint8_t* buf);
+	void import_from_bytes(uint8_t* buf);
+	void sample_fe_from_bytes(uint8_t* buf, uint32_t bytelen);
+	bool eq(fe* a);
+	void print();
+
+private:
+	void init() {
+		mpz_init(val);
+	}
+	;
+	mpz_t val;
+	prime_field* field;
+
+};
+
+class gmp_num: public num {
+public:
+	gmp_num(prime_field* fld);
+	gmp_num(prime_field* fld, mpz_t src);
+	~gmp_num();
+	void set(num* src);
+	void set_si(int32_t src);
+	void set_add(num* a, num* b);
+	void set_sub(num* a, num* b);
+	void set_mul(num* a, num* b);
+	void mod(num* mod);
+	void set_mul_mod(num* a, num* b, num* modulus) ;
+	mpz_t* get_val();
+
+	void export_to_bytes(uint8_t* buf, uint32_t field_size);
+	void import_from_bytes(uint8_t* buf, uint32_t field_size);
+	void set_rnd(uint32_t bits);
+	void print();
+
+private:
+	mpz_t val;
+	prime_field* field;
+};
+
+class gmp_brickexp: public brickexp {
+public:
+	gmp_brickexp(fe* g, prime_field* pfield) {
+		init(g, pfield);
+	}
+	;
+	~gmp_brickexp();
+
+	void pow(fe* result, num* e);
+	void init(fe* g, prime_field* pfield);
+
+private:
+	uint32_t m_numberOfElements;
+	mpz_t* m_table;
+	prime_field* field;
+};
+
+// mpz_export does not fill leading zeros, thus a prepending of leading 0s is required
+void mpz_export_padded(uint8_t* pBufIdx, uint32_t field_size, mpz_t to_export);
+
+#endif /* GMP_PK_CRYPTO_H_ */

+ 354 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/intrin_sequential_enc8.cpp

@@ -0,0 +1,354 @@
+/*
+ * Copied and modified from Shay Gueron's intrin_sequential_ks4_enc8.cpp
+ */
+/********************************************************************/
+/* Copyright(c) 2014, Intel Corp.                                   */
+/* Developers and authors: Shay Gueron (1) (2)                      */
+/* (1) University of Haifa, Israel                                  */
+/* (2) Intel, Israel                                                */
+/* IPG, Architecture, Israel Development Center, Haifa, Israel      */
+/********************************************************************/
+
+#include "intrin_sequential_enc8.h"
+
+#ifdef USE_PIPELINED_AES_NI
+
+
+#define KS_BLOCK(t, reg, reg2) {globAux=_mm_slli_epi64(reg, 32);\
+								reg=_mm_xor_si128(globAux, reg);\
+								globAux=_mm_shuffle_epi8(reg, con3);\
+								reg=_mm_xor_si128(globAux, reg);\
+								reg=_mm_xor_si128(reg2, reg);\
+								}
+
+#define KS_round(i) { x2 =_mm_shuffle_epi8(keyA, mask); \
+	keyA_aux=_mm_aesenclast_si128 (x2, con); \
+	KS_BLOCK(0, keyA, keyA_aux);\
+	x2 =_mm_shuffle_epi8(keyB, mask); \
+	keyB_aux=_mm_aesenclast_si128 (x2, con); \
+	KS_BLOCK(1, keyB, keyB_aux);\
+	x2 =_mm_shuffle_epi8(keyC, mask); \
+	keyC_aux=_mm_aesenclast_si128 (x2, con); \
+	KS_BLOCK(2, keyC, keyC_aux);\
+	x2 =_mm_shuffle_epi8(keyD, mask); \
+	keyD_aux=_mm_aesenclast_si128 (x2, con); \
+	KS_BLOCK(3, keyD, keyD_aux);\
+	con=_mm_slli_epi32(con, 1);\
+	_mm_storeu_si128((__m128i *)(keyptr[0].KEY+i*16), keyA);\
+	_mm_storeu_si128((__m128i *)(keyptr[1].KEY+i*16), keyB);	\
+	_mm_storeu_si128((__m128i *)(keyptr[2].KEY+i*16), keyC);	\
+	_mm_storeu_si128((__m128i *)(keyptr[3].KEY+i*16), keyD);	\
+	}
+
+#define KS_round_last(i) { x2 =_mm_shuffle_epi8(keyA, mask); \
+	keyA_aux=_mm_aesenclast_si128 (x2, con); \
+	x2 =_mm_shuffle_epi8(keyB, mask); \
+	keyB_aux=_mm_aesenclast_si128 (x2, con); \
+	x2 =_mm_shuffle_epi8(keyC, mask); \
+	keyC_aux=_mm_aesenclast_si128 (x2, con); \
+	x2 =_mm_shuffle_epi8(keyD, mask); \
+	keyD_aux=_mm_aesenclast_si128 (x2, con); \
+	KS_BLOCK(0, keyA, keyA_aux);\
+	KS_BLOCK(1, keyB, keyB_aux);\
+	KS_BLOCK(2, keyC, keyC_aux);\
+	KS_BLOCK(3, keyD, keyD_aux);\
+	_mm_storeu_si128((__m128i *)(keyptr[0].KEY+i*16), keyA);\
+	_mm_storeu_si128((__m128i *)(keyptr[1].KEY+i*16), keyB);	\
+	_mm_storeu_si128((__m128i *)(keyptr[2].KEY+i*16), keyC);	\
+	_mm_storeu_si128((__m128i *)(keyptr[3].KEY+i*16), keyD);	\
+	}
+
+#define READ_KEYS(i) {keyA = _mm_loadu_si128((__m128i const*)(keyptr[0].KEY+i*16));\
+	keyB = _mm_loadu_si128((__m128i const*)(keyptr[1].KEY+i*16));\
+	keyC = _mm_loadu_si128((__m128i const*)(keyptr[2].KEY+i*16));\
+	keyD = _mm_loadu_si128((__m128i const*)(keyptr[3].KEY+i*16));\
+	keyE = _mm_loadu_si128((__m128i const*)(keyptr[4].KEY+i*16));\
+	keyF = _mm_loadu_si128((__m128i const*)(keyptr[5].KEY+i*16));\
+	keyG = _mm_loadu_si128((__m128i const*)(keyptr[6].KEY+i*16));\
+	keyH = _mm_loadu_si128((__m128i const*)(keyptr[7].KEY+i*16));\
+	}
+
+#define ENC_round(i) {block1=_mm_aesenc_si128(block1, (*(__m128i const*)(keyptr[0].KEY+i*16))); \
+	block2=_mm_aesenc_si128(block2, (*(__m128i const*)(keyptr[1].KEY+i*16))); \
+	block3=_mm_aesenc_si128(block3, (*(__m128i const*)(keyptr[2].KEY+i*16))); \
+	block4=_mm_aesenc_si128(block4, (*(__m128i const*)(keyptr[3].KEY+i*16))); \
+	block5=_mm_aesenc_si128(block5, (*(__m128i const*)(keyptr[4].KEY+i*16))); \
+	block6=_mm_aesenc_si128(block6, (*(__m128i const*)(keyptr[5].KEY+i*16))); \
+	block7=_mm_aesenc_si128(block7, (*(__m128i const*)(keyptr[6].KEY+i*16))); \
+	block8=_mm_aesenc_si128(block8, (*(__m128i const*)(keyptr[7].KEY+i*16))); \
+}
+
+#define ENC_round_last(i) {block1=_mm_aesenclast_si128(block1, (*(__m128i const*)(keyptr[0].KEY+i*16))); \
+	block2=_mm_aesenclast_si128(block2, (*(__m128i const*)(keyptr[1].KEY+i*16))); \
+	block3=_mm_aesenclast_si128(block3, (*(__m128i const*)(keyptr[2].KEY+i*16))); \
+	block4=_mm_aesenclast_si128(block4, (*(__m128i const*)(keyptr[3].KEY+i*16))); \
+	block5=_mm_aesenclast_si128(block5, (*(__m128i const*)(keyptr[4].KEY+i*16))); \
+	block6=_mm_aesenclast_si128(block6, (*(__m128i const*)(keyptr[5].KEY+i*16))); \
+	block7=_mm_aesenclast_si128(block7, (*(__m128i const*)(keyptr[6].KEY+i*16))); \
+	block8=_mm_aesenclast_si128(block8, (*(__m128i const*)(keyptr[7].KEY+i*16))); \
+}
+
+
+
+
+#define KS1_BLOCK(t, reg, reg2) {globAux=_mm_slli_epi64(reg, 32);\
+								reg=_mm_xor_si128(globAux, reg);\
+								globAux=_mm_shuffle_epi8(reg, con3);\
+								reg=_mm_xor_si128(globAux, reg);\
+								reg=_mm_xor_si128(reg2, reg);\
+								}
+
+#define KS1_round(i) { x2 =_mm_shuffle_epi8(keyA, mask); \
+	keyA_aux=_mm_aesenclast_si128 (x2, con); \
+	KS1_BLOCK(0, keyA, keyA_aux);\
+	con=_mm_slli_epi32(con, 1);\
+	_mm_storeu_si128((__m128i *)(keyptr[0].KEY+i*16), keyA);\
+	}
+
+#define KS1_round_last(i) { x2 =_mm_shuffle_epi8(keyA, mask); \
+	keyA_aux=_mm_aesenclast_si128 (x2, con); \
+	KS1_BLOCK(0, keyA, keyA_aux);\
+	_mm_storeu_si128((__m128i *)(keyptr[0].KEY+i*16), keyA);\
+	}
+
+#define READ_KEYS1(i) {keyA = _mm_loadu_si128((__m128i const*)(keyptr[0].KEY+i*16));\
+	}
+
+#define ENC1_round(i) {block1=_mm_aesenc_si128(block1, (*(__m128i const*)(keyptr[0].KEY+i*16))); \
+}
+
+#define ENC1_round_last(i) {block1=_mm_aesenclast_si128(block1, (*(__m128i const*)(keyptr[0].KEY+i*16))); \
+}
+
+
+
+
+
+//generates nkeys round keys from the bytes stored in key_bytes
+void intrin_sequential_ks4(ROUND_KEYS* ks, unsigned char* key_bytes, int nkeys) {
+	ROUND_KEYS *keyptr=(ROUND_KEYS *)ks;
+	register __m128i keyA, keyB, keyC, keyD, con, mask, x2, keyA_aux, keyB_aux, keyC_aux, keyD_aux, globAux;
+	int i;
+	int _con1[4]={1,1,1,1};
+	int _con2[4]={0x1b,0x1b,0x1b,0x1b};
+	int _mask[4]={0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d};
+	int _con3[4]={0x0ffffffff, 0x0ffffffff, 0x07060504, 0x07060504};
+	__m128i con3=_mm_loadu_si128((__m128i const*)_con3);
+	int lim = (nkeys/4)*4;
+
+	for (i=0;i<lim;i+=4){
+		keyptr[0].nr=10;
+		keyptr[1].nr=10;
+		keyptr[2].nr=10;
+		keyptr[3].nr=10;
+
+		keyA = _mm_loadu_si128((__m128i const*)(key_bytes));
+		keyB = _mm_loadu_si128((__m128i const*)(key_bytes+16));
+		keyC = _mm_loadu_si128((__m128i const*)(key_bytes+32));
+		keyD = _mm_loadu_si128((__m128i const*)(key_bytes+48));
+
+		_mm_storeu_si128((__m128i *)keyptr[0].KEY, keyA);
+		_mm_storeu_si128((__m128i *)keyptr[1].KEY, keyB);
+		_mm_storeu_si128((__m128i *)keyptr[2].KEY, keyC);
+		_mm_storeu_si128((__m128i *)keyptr[3].KEY, keyD);
+
+		con = _mm_loadu_si128((__m128i const*)_con1);
+		mask = _mm_loadu_si128((__m128i const*)_mask);
+
+		KS_round(1)
+		KS_round(2)
+		KS_round(3)
+		KS_round(4)
+		KS_round(5)
+		KS_round(6)
+		KS_round(7)
+		KS_round(8)
+		con = _mm_loadu_si128((__m128i const*)_con2);
+
+		KS_round(9)
+		KS_round_last(10)
+
+		keyptr+=4;
+		key_bytes+=64;
+	}
+
+	for(; i<nkeys; i++) {
+		keyptr[0].nr=10;
+
+		keyA = _mm_loadu_si128((__m128i const*)(key_bytes));
+
+		_mm_storeu_si128((__m128i *)keyptr[0].KEY, keyA);
+
+		con = _mm_loadu_si128((__m128i const*)_con1);
+		mask = _mm_loadu_si128((__m128i const*)_mask);
+
+		KS1_round(1)
+		KS1_round(2)
+		KS1_round(3)
+		KS1_round(4)
+		KS1_round(5)
+		KS1_round(6)
+		KS1_round(7)
+		KS1_round(8)
+		con = _mm_loadu_si128((__m128i const*)_con2);
+
+		KS1_round(9)
+		KS1_round_last(10)
+
+		keyptr++;
+		key_bytes+=16;
+	}
+}
+
+void intrin_sequential_enc8(const unsigned char* PT, unsigned char* CT, int n_aesiters, int nkeys, ROUND_KEYS* ks){
+
+	ROUND_KEYS *keyptr=(ROUND_KEYS *)ks;
+    register __m128i keyA, keyB, keyC, keyD, keyE, keyF, keyG, keyH, con, mask, x2, keyA_aux, keyB_aux, keyC_aux, keyD_aux, globAux;
+    unsigned char *ptptr, ctptr;
+	int i, j, ptoffset, ctoffset;
+
+	ctoffset = n_aesiters * 16;
+
+	for (i=0;i<nkeys;i+=8){
+
+		for(j=0;j<n_aesiters; j++) {
+			register __m128i block1 = _mm_loadu_si128((__m128i const*)(0*16+PT));
+			register __m128i block2 = _mm_loadu_si128((__m128i const*)(1*16+PT));
+			register __m128i block3 = _mm_loadu_si128((__m128i const*)(2*16+PT));
+			register __m128i block4 = _mm_loadu_si128((__m128i const*)(3*16+PT));
+			register __m128i block5 = _mm_loadu_si128((__m128i const*)(4*16+PT));
+			register __m128i block6 = _mm_loadu_si128((__m128i const*)(5*16+PT));
+			register __m128i block7 = _mm_loadu_si128((__m128i const*)(6*16+PT));
+			register __m128i block8 = _mm_loadu_si128((__m128i const*)(7*16+PT));
+
+			READ_KEYS(0)
+
+			block1 = _mm_xor_si128(keyA, block1);
+			block2 = _mm_xor_si128(keyB, block2);
+			block3 = _mm_xor_si128(keyC, block3);
+			block4 = _mm_xor_si128(keyD, block4);
+			block5 = _mm_xor_si128(keyE, block5);
+			block6 = _mm_xor_si128(keyF, block6);
+			block7 = _mm_xor_si128(keyG, block7);
+			block8 = _mm_xor_si128(keyH, block8);
+
+			ENC_round(1)
+			ENC_round(2)
+			ENC_round(3)
+			ENC_round(4)
+			ENC_round(5)
+			ENC_round(6)
+			ENC_round(7)
+			ENC_round(8)
+			ENC_round(9)
+			ENC_round_last(10)
+
+			_mm_storeu_si128((__m128i *)(CT+0*16), block1);
+			_mm_storeu_si128((__m128i *)(CT+1*16), block2);
+			_mm_storeu_si128((__m128i *)(CT+2*16), block3);
+			_mm_storeu_si128((__m128i *)(CT+3*16), block4);
+			_mm_storeu_si128((__m128i *)(CT+4*16), block5);
+			_mm_storeu_si128((__m128i *)(CT+5*16), block6);
+			_mm_storeu_si128((__m128i *)(CT+6*16), block7);
+			_mm_storeu_si128((__m128i *)(CT+7*16), block8);
+
+			PT+=128;
+			CT+=128;
+
+		}
+		keyptr+=8;
+	}
+}
+
+
+
+void intrin_sequential_gen_rnd8(unsigned char* ctr_buf, const unsigned long long ctr, unsigned char* CT,
+		int n_aesiters, int nkeys, ROUND_KEYS* ks){
+
+	ROUND_KEYS *keyptr=(ROUND_KEYS *)ks;
+    register __m128i keyA, keyB, keyC, keyD, keyE, keyF, keyG, keyH, con, mask, x2, keyA_aux, keyB_aux, keyC_aux, keyD_aux, globAux;
+    unsigned char *ctptr;
+	int i, j, ctoffset;
+	unsigned long long* tmpctr = (unsigned long long*) ctr_buf;
+
+	ctoffset = n_aesiters * 16;
+
+	register __m128i inblock, block1, block2, block3, block4, block5, block6, block7, block8;
+
+	int lim = (nkeys/8)*8;
+
+	for (i=0;i<lim;i+=8){
+		ctptr=CT + i*ctoffset;
+		(*tmpctr) = ctr;
+		for(j=0;j<n_aesiters; j++) {
+			(*tmpctr)++;
+			inblock = _mm_loadu_si128((__m128i const*)(ctr_buf));
+
+			READ_KEYS(0)
+
+			block1 = _mm_xor_si128(keyA, inblock);
+			block2 = _mm_xor_si128(keyB, inblock);
+			block3 = _mm_xor_si128(keyC, inblock);
+			block4 = _mm_xor_si128(keyD, inblock);
+			block5 = _mm_xor_si128(keyE, inblock);
+			block6 = _mm_xor_si128(keyF, inblock);
+			block7 = _mm_xor_si128(keyG, inblock);
+			block8 = _mm_xor_si128(keyH, inblock);
+
+			ENC_round(1)
+			ENC_round(2)
+			ENC_round(3)
+			ENC_round(4)
+			ENC_round(5)
+			ENC_round(6)
+			ENC_round(7)
+			ENC_round(8)
+			ENC_round(9)
+			ENC_round_last(10)
+
+			_mm_storeu_si128((__m128i *)(ctptr+0*ctoffset), block1);
+			_mm_storeu_si128((__m128i *)(ctptr+1*ctoffset), block2);
+			_mm_storeu_si128((__m128i *)(ctptr+2*ctoffset), block3);
+			_mm_storeu_si128((__m128i *)(ctptr+3*ctoffset), block4);
+			_mm_storeu_si128((__m128i *)(ctptr+4*ctoffset), block5);
+			_mm_storeu_si128((__m128i *)(ctptr+5*ctoffset), block6);
+			_mm_storeu_si128((__m128i *)(ctptr+6*ctoffset), block7);
+			_mm_storeu_si128((__m128i *)(ctptr+7*ctoffset), block8);
+
+			ctptr+=16;
+		}
+		keyptr+=8;
+	}
+
+
+	for (;i<nkeys;i++){
+		ctptr=CT + i*ctoffset;
+		(*tmpctr) = ctr;
+		for(j=0;j<n_aesiters; j++) {
+			(*tmpctr)++;
+			inblock = _mm_loadu_si128((__m128i const*)(ctr_buf));
+
+			READ_KEYS1(0)
+
+			block1 = _mm_xor_si128(keyA, inblock);
+
+			ENC1_round(1)
+			ENC1_round(2)
+			ENC1_round(3)
+			ENC1_round(4)
+			ENC1_round(5)
+			ENC1_round(6)
+			ENC1_round(7)
+			ENC1_round(8)
+			ENC1_round(9)
+			ENC1_round_last(10)
+
+			_mm_storeu_si128((__m128i *)(ctptr), block1);
+
+			ctptr+=16;
+		}
+		keyptr++;
+	}
+}
+#endif
+

+ 58 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/intrin_sequential_enc8.h

@@ -0,0 +1,58 @@
+/*
+ * intrin_sequential_enc8.h
+ * Copied and modified from Shay Gueron's code from intrinsic.h
+ *
+ * Copyright(c) 2014, Intel Corp.
+ * Developers and authors: Shay Gueron (1) (2)
+ * (1) University of Haifa, Israel
+ * (2) Intel, Israel
+ * IPG, Architecture, Israel Development Center, Haifa, Israel
+ */
+
+#include "../constants.h"
+
+#ifndef INTRIN_SEQUENTIAL_ENC8_H_
+#define INTRIN_SEQUENTIAL_ENC8_H_
+
+#ifdef USE_PIPELINED_AES_NI
+
+#include <stdint.h>
+#include <stdio.h>
+#include <wmmintrin.h>
+
+#if !defined (ALIGN16)
+#if defined (__GNUC__)
+#  define ALIGN16  __attribute__  ( (aligned (16)))
+# else
+#  define ALIGN16 __declspec (align (16))
+# endif
+#endif
+
+#if defined(__INTEL_COMPILER)
+# include <ia32intrin.h>
+#elif defined(__GNUC__)
+# include <emmintrin.h>
+# include <smmintrin.h>
+#endif
+
+typedef struct KEY_SCHEDULE
+{
+	ALIGN16 unsigned char KEY[16*15];
+	unsigned int nr;
+} ROUND_KEYS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	void intrin_sequential_gen_rnd8(unsigned char* ctr_buf, const unsigned long long ctr, unsigned char* CT,
+		int n_aesiters, int nkeys, ROUND_KEYS* ks);
+	void intrin_sequential_ks4(ROUND_KEYS* ks, unsigned char* key_bytes, int nkeys);
+	void intrin_sequential_enc8(const unsigned char* PT, unsigned char* CT, int aes_niters, int nkeys, ROUND_KEYS* ks);
+
+#ifdef __cplusplus
+};
+#endif
+#endif /* USE_PIPELINED_AES_NI */
+
+#endif /* INTRIN_SEQUENTIAL_ENC8_H_ */

+ 114 - 0
2p-preprocessing/ENCRYPTO_utils/crypto/pk-crypto.h

@@ -0,0 +1,114 @@
+/**
+ \file 		pk-crypto.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Virtual class for public-key operations
+ */
+
+#ifndef PK_CRYPTO_H_
+#define PK_CRYPTO_H_
+
+#include "../typedefs.h"
+#include "../constants.h"
+#include "../utils.h"
+
+class pk_crypto;
+class num;
+class fe;
+class brickexp;
+
+class pk_crypto {
+public:
+	pk_crypto(seclvl sp) {
+		fe_bytelen = 0;
+		order = 0;
+		secparam = sp;
+	}
+	;
+	virtual ~pk_crypto() {};
+	virtual num* get_num() = 0;
+	virtual num* get_rnd_num(uint32_t bitlen = 0) = 0;
+	virtual fe* get_fe() = 0;
+	virtual fe* get_rnd_fe() = 0;
+	virtual fe* get_generator() = 0;
+	virtual fe* get_rnd_generator() = 0;
+	virtual uint32_t num_byte_size() = 0;
+	virtual num* get_order() = 0;
+	uint32_t fe_byte_size() {
+		return fe_bytelen;
+	}
+	;
+	virtual uint32_t get_field_size() = 0;
+	virtual brickexp* get_brick(fe* gen) = 0;
+
+protected:
+	virtual void init(seclvl secparam, uint8_t* seed) = 0;
+	uint32_t fe_bytelen;
+	seclvl secparam;
+	num* order;
+};
+
+//class number
+class num {
+public:
+	num() {
+
+	}
+	;
+	virtual ~num() {};
+	virtual void set(num* src) = 0;
+	virtual void set_si(int32_t src) = 0;
+	virtual void set_add(num* a, num* b) = 0;
+	virtual void set_sub(num* a, num* b) = 0;
+	virtual void set_mul(num* a, num* b) = 0;
+	virtual void mod(num* modulus) = 0;
+	virtual void set_mul_mod(num* a, num* b, num* modulus) = 0;
+	virtual void export_to_bytes(uint8_t* buf, uint32_t field_size) = 0;
+	virtual void import_from_bytes(uint8_t* buf, uint32_t field_size) = 0;
+	virtual void print() = 0;
+};
+
+//class field_element
+class fe {
+public:
+	fe() {
+	}
+	;
+	virtual ~fe() {};
+	virtual void set(fe* src) = 0;
+	virtual void set_mul(fe* a, fe* b) = 0;
+	virtual void set_pow(fe* b, num* e) = 0;
+	virtual void set_div(fe* a, fe* b) = 0;
+	virtual void set_double_pow_mul(fe* b1, num* e1, fe* b2, num* e2) = 0;
+	virtual void export_to_bytes(uint8_t* buf) = 0;
+	virtual void import_from_bytes(uint8_t* buf) = 0;
+	virtual void sample_fe_from_bytes(uint8_t* buf, uint32_t bytelen) = 0;
+	virtual void print() = 0;
+	virtual bool eq(fe* a) = 0;
+
+protected:
+	virtual void init() = 0;
+};
+
+class brickexp {
+public:
+	brickexp() {
+	}
+	;
+	virtual ~brickexp() {};
+
+	virtual void pow(fe* result, num* e) = 0;
+};
+
+#endif /* PK_CRYPTO_H_ */

+ 144 - 0
2p-preprocessing/ENCRYPTO_utils/parse_options.cpp

@@ -0,0 +1,144 @@
+/**
+ \file 		parse_options.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Parse Options Implementation
+ */
+
+#include "parse_options.h"
+#include <cstring>
+#include <iostream>
+
+/**
+ * takes a string in the Format "c i i i ..."
+ * (1 char followed by potentially many integers) and returns a vector of all i
+ * @param str the string to tokenize
+ * @param tokens the result vector of wire id
+ */
+void tokenize_verilog(const std::string& str, std::vector<uint32_t>& tokens, const std::string& delimiters) {
+
+	tokens.clear();
+
+	// Skip delimiters at beginning. Skip first two characters (1 Char + 1 Space)
+	std::string::size_type lastPos = str.find_first_not_of(delimiters, 2);
+
+	// Find first "non-delimiter".
+	std::string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+	while (std::string::npos != pos || std::string::npos != lastPos) {
+		// Found a token, add it to the vector.
+		tokens.push_back(atoi(str.substr(lastPos, pos - lastPos).c_str()));
+		// Skip delimiters.  Note the "not_of"
+		lastPos = str.find_first_not_of(delimiters, pos);
+		// Find next "non-delimiter"
+		pos = str.find_first_of(delimiters, lastPos);
+	}
+}
+
+/**
+ * takes a string in the Format "i|i|i|..."
+ * (integers separated by '|') and returns a vector of all integers
+ * @param str the string to tokenize
+ * @param tokens the result vector of wire id
+ */
+void tokenize(const std::string& str, std::vector<uint32_t>& tokens, const std::string& delimiters) {
+
+	tokens.clear();
+
+	// Skip delimiters at beginning
+	std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+
+	// Find first "non-delimiter".
+	std::string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+	while (std::string::npos != pos || std::string::npos != lastPos) {
+		// Found a token, add it to the vector.
+		tokens.push_back(atoi(str.substr(lastPos, pos - lastPos).c_str()));
+		// Skip delimiters.  Note the "not_of"
+		lastPos = str.find_first_not_of(delimiters, pos);
+		// Find next "non-delimiter"
+		pos = str.find_first_of(delimiters, lastPos);
+	}
+}
+
+int32_t parse_options(int32_t* argcp, char*** argvp, parsing_ctx* options, uint32_t nops) {
+	int result = 0;
+	bool skip;
+	uint32_t i;
+	if(*argcp < 2)
+		return 0;
+
+	while ((*argcp) > 1) {
+		if ((*argvp)[1][0] != '-' || (*argvp)[1][1] == '\0' || (*argvp)[1][2] != '\0'){
+			return result;
+		}
+		skip=false;
+		for (i = 0, skip = false; i < nops && !skip; i++) {
+			if (strncmp(&((*argvp)[1][1]), options[i].opt_name.c_str(), options[i].opt_name.size()) == 0
+					&& (strlen((*argvp)[1])-1 == options[i].opt_name.size())) {
+
+				switch (options[i].type) {
+				case T_NUM:
+					if (isdigit((*argvp)[2][0])) {
+						++*argvp;
+						--*argcp;
+						*((uint32_t*) options[i].val) = atoi((*argvp)[1]);
+					} else {
+					    std::cerr << "Argument for parameter wrong. " << std::endl;
+						return 0;
+					}
+					break;
+				case T_DOUBLE:
+					++*argvp;
+					--*argcp;
+					*((double*) options[i].val) = atof((*argvp)[1]);
+					break;
+				case T_STR:
+					++*argvp;
+					--*argcp;
+					*((std::string*) options[i].val) = (*argvp)[1];
+					break;
+				case T_FLAG:
+					*((bool*) options[i].val) = true;
+					break;
+				}
+				++result;
+				++*argvp;
+				--*argcp;
+				options[i].set = true;
+				skip = true;
+			}
+		}
+		if(skip == false) {
+		    std::cerr << "Parameter not recognized. " << std::endl;
+			return 0;
+		}
+	}
+
+	for (i = 0; i < nops; i++) {
+		if (options[i].required && !options[i].set)
+			return 0;
+	}
+	return 1;
+}
+
+void print_usage(std::string progname, parsing_ctx* options, uint32_t nops) {
+	uint32_t i;
+	std::cout << "Usage: " << progname << std::endl;
+	for (i = 0; i < nops; i++) {
+		std::cout << " -" << options[i].opt_name << " [" << options[i].help_str << (options[i].required ? ", required" : ", optional") << "]" << std::endl;
+	}
+	std::cout << std::endl << "Program exiting" << std::endl;
+}
+

+ 76 - 0
2p-preprocessing/ENCRYPTO_utils/parse_options.h

@@ -0,0 +1,76 @@
+/**
+ \file 		parse_options.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Parse Options Implementation
+ */
+
+#ifndef UTIL_PARSE_OPTIONS_H_
+#define UTIL_PARSE_OPTIONS_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+/**
+ \enum 	etype
+ \brief	Data types for command line parameters
+ */
+enum etype {
+	T_NUM, //uint32_t number
+	T_STR, //string
+	T_FLAG, //boolean flag
+	T_DOUBLE //double number
+};
+
+
+/**
+ \struct 	parsing_ctx
+ \brief	holds information about parameters that should be parsed in the command line input
+ */
+struct parsing_ctx {
+	void* val;	//value of the option, is written into by parse_options
+	etype type;	//type of value
+	std::string opt_name; //name to set the parameter via command line
+	std::string help_str; //definition of the parameter that is printed in print_usage
+	bool required; //is the parameter required to run the program? If required and not set by the invocation, program will exit
+	bool set; //has the value for the parameter been set previously? In case the parameter is read, this will be set to true
+};
+
+
+/**
+	This method parses the command line arguments from a C program, given in argcp and argcv, using the flags and parameters specified
+	in options where nops gives the number of parameters that are parsed. The values for the parameters are written into options.
+
+	\param  argcp	 - Pointer to argc
+	\param  argvp	 - Pointer to argv
+	\param	options  - A list of parameters that the command line input should be parsed for
+	\param	nops	 - Number of parameters in options
+	\return	0 if the command line string was faulty and 1 otherwise.
+*/
+int32_t parse_options(int32_t* argcp, char*** argvp, parsing_ctx* options, uint32_t nops);
+
+/**
+	This method prints the command line parameters together with a short help description in help_str
+
+	\param  progname	- Name of the program
+	\param  options		- Parameters that should be printed
+	\param	nops	 	- Number of parameters in options
+
+*/
+void print_usage(std::string progname, parsing_ctx* options, uint32_t nops);
+void tokenize(const std::string& str, std::vector<uint32_t>& tokens, const std::string& delimiters = "| \t");
+void tokenize_verilog(const std::string& str, std::vector<uint32_t>& tokens, const std::string& delimiters = " \t");
+
+#endif /* PARSE_OPTIONS_H_ */

+ 175 - 0
2p-preprocessing/ENCRYPTO_utils/powmod.cpp

@@ -0,0 +1,175 @@
+/**
+ \file 		powmod.cpp
+ \author 	daniel.demmler@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		PowMod Implementation
+ */
+
+#include "powmod.h"
+#include <cstdlib>
+
+#define POWMOD_DEBUG 0
+
+#if POWMOD_DEBUG
+#include <cstdio>
+#endif
+
+mpz_t* m_table_g;
+mpz_t* m_table_h;
+mpz_t* m_prod;
+mpz_t m_mod;
+size_t m_numberOfElements_g, m_numberOfElements_h;
+
+void fbpowmod_init_g(const mpz_t base, const mpz_t mod, size_t bitsize) {
+	m_numberOfElements_g = bitsize;
+	mpz_init(m_mod);
+	mpz_set(m_mod, mod);
+	m_table_g = (mpz_t*) malloc(sizeof(mpz_t) * bitsize);
+	for (size_t i = 0; i < bitsize; i++) {
+		mpz_init(m_table_g[i]);
+	}
+
+	mpz_set(m_table_g[0], base);
+	for (size_t u = 1; u < bitsize; u++) {
+		mpz_mul(m_table_g[u], m_table_g[u - 1], m_table_g[u - 1]);
+		mpz_mod(m_table_g[u], m_table_g[u], mod);
+	}
+}
+
+void fbpowmod_init_h(const mpz_t base, const mpz_t mod, size_t bitsize) {
+	m_numberOfElements_h = bitsize;
+	mpz_init(m_mod);
+	mpz_set(m_mod, mod);
+	m_table_h = (mpz_t*) malloc(sizeof(mpz_t) * bitsize);
+	for (size_t i = 0; i < bitsize; i++) {
+		mpz_init(m_table_h[i]);
+	}
+
+	mpz_set(m_table_h[0], base);
+	for (size_t u = 1; u < bitsize; u++) {
+		mpz_mul(m_table_h[u], m_table_h[u - 1], m_table_h[u - 1]);
+		mpz_mod(m_table_h[u], m_table_h[u], mod);
+	}
+}
+
+void fbpowmod_g(mpz_t result, const mpz_t exp) {
+	auto top = mpz_sizeinbase(exp, 2);
+	if (top <= m_numberOfElements_g) {
+		mpz_set_ui(result, 1);
+
+		for (size_t u = 0; u < top; u++) {
+			if (mpz_tstbit(exp, u)) {
+				mpz_mul(result, result, m_table_g[u]);
+				mpz_mod(result, result, m_mod);
+			}
+		}
+	} else {
+		printf("(g) Exponent too big for pre-computed fixed-base powmod! %zu %zu\n", top, m_numberOfElements_g);
+	}
+}
+
+void fbpowmod_h(mpz_t result, const mpz_t exp) {
+	auto top = mpz_sizeinbase(exp, 2);
+	if (top <= m_numberOfElements_h) {
+		mpz_set_ui(result, 1);
+
+		for (size_t u = 0; u < top; u++) {
+			if (mpz_tstbit(exp, u)) {
+				mpz_mul(result, result, m_table_h[u]);
+				mpz_mod(result, result, m_mod);
+			}
+		}
+	} else {
+		printf("Exponent too big for pre-computed fixed-base powmod! %zu %zu\n", top, m_numberOfElements_h);
+	}
+}
+
+void dbpowmod(mpz_t ret, const mpz_t b1, const mpz_t e1, const mpz_t b2, const mpz_t e2, const mpz_t mod) {
+	unsigned char index;
+	mpz_t prod[3];
+
+	auto size = (mpz_cmp(e1, e2) > 0) ? mpz_sizeinbase(e1, 2) : mpz_sizeinbase(e2, 2);
+
+#if POWMOD_DEBUG
+	printf("size: %zu\n", size);
+#endif
+
+	mpz_init_set(prod[0], b1);
+	mpz_init_set(prod[1], b2);
+	mpz_init(prod[2]);
+
+	mpz_mul(prod[2], b1, b2);
+	mpz_mod(prod[2], prod[2], mod);
+
+	mpz_set_ui(ret, 1);
+	for (ssize_t i = size - 1; i >= 0; i--) {
+		index = (mpz_tstbit(e2, i) << 1) + mpz_tstbit(e1, i);
+
+#if POWMOD_DEBUG
+		gmp_printf("%d | %Zd", index, ret);
+#endif
+
+		mpz_mul(ret, ret, ret);
+		mpz_mod(ret, ret, mod);
+
+#if POWMOD_DEBUG
+		gmp_printf(" - sq:%Zd", ret);
+#endif
+
+		if (index) {
+			mpz_mul(ret, prod[index - 1], ret);
+			mpz_mod(ret, ret, mod);
+		}
+
+#if POWMOD_DEBUG
+		gmp_printf(" -  end:%Zd\n", ret);
+#endif
+	}
+
+	mpz_clears(prod[0], prod[1], prod[2], NULL);
+}
+
+void fbdbpowmod_init(const mpz_t b1, const mpz_t b2, const mpz_t mod, size_t) {
+
+	mpz_init(m_mod);
+	mpz_set(m_mod, mod);
+
+	m_prod = (mpz_t*) malloc(sizeof(mpz_t) * 3);
+
+	mpz_init_set(m_prod[0], b1);
+	mpz_init_set(m_prod[1], b2);
+	mpz_init(m_prod[2]);
+	mpz_mul(m_prod[2], b1, b2);
+	mpz_mod(m_prod[2], m_prod[2], mod);
+}
+
+void fbdbpowmod(mpz_t ret, const mpz_t e1, const mpz_t e2) {
+
+	unsigned char index;
+
+	auto size = (mpz_cmp(e1, e2) > 0) ? mpz_sizeinbase(e1, 2) : mpz_sizeinbase(e2, 2);
+
+	mpz_set_ui(ret, 1);
+	for (ssize_t i = size - 1; i >= 0; i--) {
+		index = (mpz_tstbit(e2, i) << 1) + mpz_tstbit(e1, i);
+
+		mpz_mul(ret, ret, ret);
+		mpz_mod(ret, ret, m_mod);
+
+		if (index) {
+			mpz_mul(ret, m_prod[index - 1], ret);
+			mpz_mod(ret, ret, m_mod);
+		}
+	}
+}

+ 57 - 0
2p-preprocessing/ENCRYPTO_utils/powmod.h

@@ -0,0 +1,57 @@
+/**
+ \file 		powmod.h
+ \author 	daniel.demmler@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Powmod Implementation
+ */
+
+#ifndef _POWMOD_H_
+#define _POWMOD_H_
+
+#include <gmp.h>
+
+extern mpz_t* m_table_g;
+extern mpz_t* m_table_h;
+extern mpz_t* m_prod;
+extern mpz_t m_mod;
+extern size_t m_numberOfElements_g;
+extern size_t m_numberOfElements_h;
+
+/**
+ * initialize fixed base multiplication for a given base and a desired exponent bit size
+ * identical functionality for either g or h
+ */
+void fbpowmod_init_g(const mpz_t base, const mpz_t mod, size_t bitsize);
+void fbpowmod_init_h(const mpz_t base, const mpz_t mod, size_t bitsize);
+
+/**
+ * fixed-base multiplication
+ * requires pre-computed table, created with fbpowmod_init_*
+ */
+void fbpowmod_g(mpz_t result, const mpz_t exp);
+void fbpowmod_h(mpz_t result, const mpz_t exp);
+
+/**
+ * fixed-base double base encryption
+ * requires pre-computed product with fbdbpowmod_init
+ */
+void fbdbpowmod(mpz_t ret, const mpz_t e1, const mpz_t e2);
+void fbdbpowmod_init(const mpz_t b1, const mpz_t b2, const mpz_t mod, size_t bitsize);
+
+/**
+ * double-base exponentiation ret = b1^e1*b2^e2
+ */
+void dbpowmod(mpz_t ret, const mpz_t b1, const mpz_t e1, const mpz_t b2, const mpz_t e2, const mpz_t mod);
+
+#endif

+ 170 - 0
2p-preprocessing/ENCRYPTO_utils/rcvthread.cpp

@@ -0,0 +1,170 @@
+/**
+ \file 		rcvthread.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+
+#include "rcvthread.h"
+#include "typedefs.h"
+#include "constants.h"
+#include "socket.h"
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+
+
+RcvThread::RcvThread(CSocket* sock, CLock *glock)
+	:rcvlock(glock),  mysock(sock), listeners()
+{
+	listeners[ADMIN_CHANNEL].inuse = true;
+}
+
+RcvThread::~RcvThread() {
+	this->Wait();
+	for(size_t i = 0; i < listeners.size(); i++) {
+		flush_queue(i);
+	}
+	//delete rcvlock;
+}
+
+CLock* RcvThread::getlock() const {
+	return rcvlock;
+}
+
+void RcvThread::setlock(CLock *glock) {
+	rcvlock = glock;
+}
+
+void RcvThread::flush_queue(uint8_t channelid) {
+	std::lock_guard<std::mutex> lock(listeners[channelid].rcv_buf_mutex);
+	while(!listeners[channelid].rcv_buf.empty()) {
+		rcv_ctx* tmp = listeners[channelid].rcv_buf.front();
+		free(tmp->buf);
+		free(tmp);
+		listeners[channelid].rcv_buf.pop();
+	}
+}
+
+void RcvThread::remove_listener(uint8_t channelid) {
+	rcvlock->Lock();
+	if(listeners[channelid].inuse) {
+		listeners[channelid].fin_event->Set();
+		listeners[channelid].inuse = false;
+
+#ifdef DEBUG_RECEIVE_THREAD
+		std::cout << "Unsetting channel " << (uint32_t) channelid << std::endl;
+#endif
+	} else {
+		listeners[channelid].forward_notify_fin = true;
+	}
+	rcvlock->Unlock();
+
+}
+
+std::queue<rcv_ctx*>*
+RcvThread::add_listener(uint8_t channelid, CEvent* rcv_event, CEvent* fin_event) {
+	rcvlock->Lock();
+#ifdef DEBUG_RECEIVE_THREAD
+	std::cout << "Registering listener on channel " << (uint32_t) channelid << std::endl;
+#endif
+
+	if(listeners[channelid].inuse || channelid == ADMIN_CHANNEL) {
+		std::cerr << "A listener has already been registered on channel " << (uint32_t) channelid << std::endl;
+		assert(!listeners[channelid].inuse);
+		assert(channelid != ADMIN_CHANNEL);
+	}
+
+	//listeners[channelid].rcv_buf = rcv_buf;
+	listeners[channelid].rcv_event = rcv_event;
+	listeners[channelid].fin_event = fin_event;
+	listeners[channelid].inuse = true;
+//		assert(listeners[channelid].rcv_buf->empty());
+
+	//std::cout << "Successfully registered on channel " << (uint32_t) channelid << std::endl;
+
+	rcvlock->Unlock();
+
+	if(listeners[channelid].forward_notify_fin) {
+		listeners[channelid].forward_notify_fin = false;
+		remove_listener(channelid);
+	}
+	return &listeners[channelid].rcv_buf;
+}
+
+std::mutex& RcvThread::get_listener_mutex(uint8_t channelid)
+{
+	return listeners[channelid].rcv_buf_mutex;
+}
+
+
+void RcvThread::ThreadMain() {
+	uint8_t channelid;
+	uint64_t rcvbytelen;
+	uint64_t rcv_len;
+	while(true) {
+		//std::cout << "Starting to receive data" << std::endl;
+		rcv_len = 0;
+		rcv_len += mysock->Receive(&channelid, sizeof(uint8_t));
+		rcv_len += mysock->Receive(&rcvbytelen, sizeof(uint64_t));
+
+		if(rcv_len > 0) {
+#ifdef DEBUG_RECEIVE_THREAD
+			std::cout << "Received value on channel " << (uint32_t) channelid << " with " << rcvbytelen <<
+					" bytes length (" << rcv_len << ")" << std::endl;
+#endif
+
+			if(channelid == ADMIN_CHANNEL) {
+				std::vector<uint8_t> tmprcvbuf(rcvbytelen);
+				mysock->Receive(tmprcvbuf.data(), rcvbytelen);
+
+				//TODO: Right now finish, can be used for other maintenance tasks
+				//std::cout << "Got message on Admin channel, shutting down" << std::endl;
+#ifdef DEBUG_RECEIVE_THREAD
+				std::cout << "Receiver thread is being killed" << std::endl;
+#endif
+				return;//continue;
+			}
+
+			if(rcvbytelen == 0) {
+				remove_listener(channelid);
+			} else {
+				rcv_ctx* rcv_buf = (rcv_ctx*) malloc(sizeof(rcv_ctx));
+				rcv_buf->buf = (uint8_t*) malloc(rcvbytelen);
+				rcv_buf->rcvbytes = rcvbytelen;
+
+				mysock->Receive(rcv_buf->buf, rcvbytelen);
+				rcvlock->Lock();
+
+				{
+					std::lock_guard<std::mutex> lock(listeners[channelid].rcv_buf_mutex);
+					listeners[channelid].rcv_buf.push(rcv_buf);
+				}
+
+				bool cond = listeners[channelid].inuse;
+				rcvlock->Unlock();
+
+				if(cond)
+					listeners[channelid].rcv_event->Set();
+			}
+		} else {
+			// We received 0 bytes, probably due to some major error. Just return.
+			// TODO: Probably add some more elaborate error handling.
+			return;
+		}
+
+	}
+
+}

+ 76 - 0
2p-preprocessing/ENCRYPTO_utils/rcvthread.h

@@ -0,0 +1,76 @@
+/**
+ \file 		rcvthread.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+#ifndef RCV_THREAD_H_
+#define RCV_THREAD_H_
+
+#include "constants.h"
+#include "thread.h"
+#include <array>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+class CSocket;
+
+struct rcv_ctx {
+	uint8_t *buf;
+	uint64_t rcvbytes;
+};
+
+
+
+class RcvThread: public CThread {
+public:
+	RcvThread(CSocket* sock, CLock* glock);
+	~RcvThread();
+
+	CLock* getlock() const;
+
+    void setlock(CLock *glock);
+
+	void flush_queue(uint8_t channelid);
+
+	void remove_listener(uint8_t channelid);
+
+	std::queue<rcv_ctx*>* add_listener(uint8_t channelid, CEvent* rcv_event, CEvent* fin_event);
+	std::mutex& get_listener_mutex(uint8_t channelid);
+
+	void ThreadMain();
+
+private:
+	//A receive task listens to a particular id and writes incoming data on that id into rcv_buf and triggers event
+	struct rcv_task {
+		std::queue<rcv_ctx*> rcv_buf;
+		std::mutex rcv_buf_mutex;
+		//std::queue<uint64_t> rcvbytes;
+		CEvent* rcv_event;
+		CEvent* fin_event;
+		bool inuse;
+		bool forward_notify_fin;
+	};
+
+	CLock* rcvlock;
+	CSocket* mysock;
+	std::array<rcv_task, MAX_NUM_COMM_CHANNELS> listeners;
+};
+
+
+
+#endif /* RCV_THREAD_H_ */

+ 158 - 0
2p-preprocessing/ENCRYPTO_utils/sndthread.cpp

@@ -0,0 +1,158 @@
+/**
+ \file 		sndthread.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+
+#include "sndthread.h"
+#include "socket.h"
+#include "constants.h"
+#include <cassert>
+#include <cstring>
+
+
+SndThread::SndThread(CSocket* sock, CLock *glock)
+: mysock(sock), sndlock(glock), send(std::make_unique<CEvent>())
+{
+}
+
+void SndThread::stop() {
+	kill_task();
+}
+
+SndThread::~SndThread() {
+	kill_task();
+	this->Wait();
+}
+
+CLock* SndThread::getlock() const {
+	return sndlock;
+}
+
+void SndThread::setlock(CLock *glock) {
+	sndlock = glock;
+}
+
+void SndThread::push_task(std::unique_ptr<snd_task> task)
+{
+	sndlock->Lock();
+	send_tasks.push(std::move(task));
+	sndlock->Unlock();
+	send->Set();
+}
+
+void SndThread::add_event_snd_task_start_len(CEvent* eventcaller, uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf, uint64_t startid, uint64_t len) {
+	assert(channelid != ADMIN_CHANNEL);
+	auto task = std::make_unique<snd_task>();
+	task->channelid = channelid;
+	task->eventcaller = eventcaller;
+	size_t bytelen = sndbytes + 2 * sizeof(uint64_t);
+	task->snd_buf.resize(bytelen);
+	memcpy(task->snd_buf.data(), &startid, sizeof(uint64_t));
+	memcpy(task->snd_buf.data()+sizeof(uint64_t), &len, sizeof(uint64_t));
+	memcpy(task->snd_buf.data()+2*sizeof(uint64_t), sndbuf, sndbytes);
+
+	//std::cout << "Adding a new task that is supposed to send " << task->bytelen << " bytes on channel " << (uint32_t) channelid  << std::endl;
+	push_task(std::move(task));
+}
+
+void SndThread::add_snd_task_start_len(uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf, uint64_t startid, uint64_t len) {
+	//Call the method blocking but since callback is nullptr nobody gets notified, other functionallity is equal
+	add_event_snd_task_start_len(nullptr, channelid, sndbytes, sndbuf, startid, len);
+}
+
+
+void SndThread::add_event_snd_task(CEvent* eventcaller, uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf) {
+	assert(channelid != ADMIN_CHANNEL);
+	auto task = std::make_unique<snd_task>();
+	task->channelid = channelid;
+	task->eventcaller = eventcaller;
+	task->snd_buf.resize(sndbytes);
+	memcpy(task->snd_buf.data(), sndbuf, sndbytes);
+
+	push_task(std::move(task));
+	//std::cout << "Event set" << std::endl;
+
+}
+
+void SndThread::add_snd_task(uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf) {
+	//Call the method blocking but since callback is nullptr nobody gets notified, other functionallity is equal
+	add_event_snd_task(nullptr, channelid, sndbytes, sndbuf);
+}
+
+void SndThread::signal_end(uint8_t channelid) {
+	add_snd_task(channelid, 0, nullptr);
+	//std::cout << "Signalling end on channel " << (uint32_t) channelid << std::endl;
+}
+
+void SndThread::kill_task() {
+	auto task = std::make_unique<snd_task>();
+	task->channelid = ADMIN_CHANNEL;
+	task->snd_buf = {0};
+
+	push_task(std::move(task));
+#ifdef DEBUG_SEND_THREAD
+	std::cout << "Killing channel " << (uint32_t) task->channelid << std::endl;
+#endif
+}
+
+void SndThread::ThreadMain() {
+	uint8_t channelid;
+	uint32_t iters;
+	bool run = true;
+	bool empty = true;
+	while(run) {
+		sndlock->Lock();
+		empty = send_tasks.empty();
+		sndlock->Unlock();
+
+		if(empty){
+			send->Wait();
+		}
+		//std::cout << "Awoken" << std::endl;
+
+		sndlock->Lock();
+		iters = send_tasks.size();
+		sndlock->Unlock();
+
+		while((iters--) && run) {
+			sndlock->Lock();
+			auto task = std::move(send_tasks.front());
+			send_tasks.pop();
+			sndlock->Unlock();
+			channelid = task->channelid;
+			mysock->Send(&channelid, sizeof(uint8_t));
+			uint64_t bytelen = task->snd_buf.size();
+			mysock->Send(&bytelen, sizeof(bytelen));
+			if(bytelen > 0) {
+				mysock->Send(task->snd_buf.data(), task->snd_buf.size());
+			}
+
+#ifdef DEBUG_SEND_THREAD
+			std::cout << "Sending on channel " <<  (uint32_t) channelid << " a message of " << task->bytelen << " bytes length" << std::endl;
+#endif
+
+			if(channelid == ADMIN_CHANNEL) {
+				//delete sndlock;
+				run = false;
+			}
+			if(task->eventcaller != nullptr) {
+				task->eventcaller->Set();
+			}
+		}
+	}
+}
+;

+ 73 - 0
2p-preprocessing/ENCRYPTO_utils/sndthread.h

@@ -0,0 +1,73 @@
+/**
+ \file 		sndthread.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+
+#ifndef SND_THREAD_H_
+#define SND_THREAD_H_
+
+#include "thread.h"
+#include <memory>
+#include <queue>
+
+class CSocket;
+
+
+class SndThread: public CThread {
+public:
+	SndThread(CSocket* sock, CLock *glock);
+
+	void stop();
+
+	~SndThread();
+
+	CLock* getlock() const;
+
+    void setlock(CLock *glock);
+
+	void add_snd_task_start_len(uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf, uint64_t startid, uint64_t len);
+
+	void add_event_snd_task_start_len(CEvent* eventcaller, uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf, uint64_t startid, uint64_t len);
+
+	void add_snd_task(uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf);
+
+	void add_event_snd_task(CEvent* eventcaller, uint8_t channelid, uint64_t sndbytes, uint8_t* sndbuf);
+
+	void signal_end(uint8_t channelid);
+
+	void kill_task();
+
+	void ThreadMain();
+
+private:
+	struct snd_task {
+		uint8_t channelid;
+		std::vector<uint8_t> snd_buf;
+		CEvent* eventcaller;
+	};
+
+	void push_task(std::unique_ptr<snd_task> task);
+
+	CSocket* mysock;
+	CLock* sndlock;
+	std::unique_ptr<CEvent> send;
+	std::queue<std::unique_ptr<snd_task>> send_tasks;
+};
+
+
+
+#endif /* SND_THREAD_H_ */

+ 264 - 0
2p-preprocessing/ENCRYPTO_utils/socket.cpp

@@ -0,0 +1,264 @@
+/**
+ \file 		socket.cpp
+ \author 	Seung Geol Choi
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+ Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+This program 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 3 of the License, or
+(at your option) any later version.
+ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Socket Implementation
+ */
+
+#include "socket.h"
+#include "utils.h"
+
+
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+
+#include <boost/asio/connect.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/ip/address.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ip/v6_only.hpp>
+#include <boost/asio/read.hpp>
+#include <boost/asio/write.hpp>
+using boost::asio::ip::tcp;
+
+
+struct CSocket::CSocketImpl {
+	CSocketImpl(std::shared_ptr<boost::asio::io_context> io_context,
+			tcp::socket&& socket)
+		: io_context(io_context), socket(std::move(socket)),
+		acceptor(*io_context)
+	{
+	}
+	CSocketImpl()
+		: io_context(std::make_shared<boost::asio::io_context>()),
+		socket(*io_context), acceptor(*io_context)
+	{}
+	std::shared_ptr<boost::asio::io_context> io_context;
+	tcp::socket socket;
+	tcp::acceptor acceptor;
+};
+
+CSocket::CSocket(bool verbose)
+	: impl_(std::make_unique<CSocketImpl>()), send_count_(0), recv_count_(0),
+	verbose_(verbose)
+{}
+
+CSocket::~CSocket() {
+	Close();
+}
+
+uint64_t CSocket::getSndCnt() const {
+	std::lock_guard<std::mutex> lock(send_count_mutex_);
+	return send_count_;
+}
+uint64_t CSocket::getRcvCnt() const {
+	std::lock_guard<std::mutex> lock(recv_count_mutex_);
+	return recv_count_;
+}
+void CSocket::ResetSndCnt() {
+	std::lock_guard<std::mutex> lock(send_count_mutex_);
+	send_count_ = 0;
+}
+void CSocket::ResetRcvCnt() {
+	std::lock_guard<std::mutex> lock(recv_count_mutex_);
+	recv_count_ = 0;
+}
+
+bool CSocket::Socket() {
+	return true;
+}
+
+void CSocket::Close() {
+	impl_->socket.close();
+}
+
+std::string CSocket::GetIP() const {
+	boost::system::error_code ec;
+	auto endpoint = impl_->socket.local_endpoint(ec);
+	if (ec) {
+		return "";
+	}
+	return endpoint.address().to_string();
+}
+
+uint16_t CSocket::GetPort() const {
+	boost::system::error_code ec;
+	auto endpoint = impl_->socket.local_endpoint(ec);
+	if (ec) {
+		return 0;
+	}
+	return endpoint.port();
+}
+
+bool CSocket::Bind(const std::string& ip, uint16_t port) {
+	boost::system::error_code ec;
+	boost::asio::ip::address address;
+
+	if (ip.empty()) {
+		// Use "::" if no address is given
+		address = boost::asio::ip::address_v6();
+	} else {
+		// Try to parse given address
+		address = boost::asio::ip::make_address(ip, ec);
+		if (ec) {
+			if (verbose_) {
+				std::cerr << "make_address failed: " << ec.message() << "\n";
+				std::cerr << "with argument: " << ip << "\n";
+			}
+			return false;
+		}
+	}
+
+	tcp::endpoint endpoint(address, port);
+
+	impl_->acceptor.open(endpoint.protocol(), ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "acceptor socket open failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << endpoint << "\n";
+		}
+		return false;
+	}
+
+	// Use dual stack IPv4 and IPv6
+	if (endpoint.protocol() == tcp::v6()) {
+		boost::asio::ip::v6_only opt(false);
+		impl_->acceptor.set_option(opt, ec);
+		if (ec) {
+			if (verbose_) {
+				std::cerr << "acceptor disable option IPPROTO_IPV6/IP_V6ONLY failed: "
+					<< ec.message() << "\n";
+			}
+			return false;
+		}
+	}
+	
+	// Set socket options
+	boost::asio::socket_base::reuse_address opt_reuse_addr(true);
+	tcp::no_delay opt_tcp_no_delay(true);
+	impl_->acceptor.set_option(opt_reuse_addr, ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "acceptor set option SO_REUSEADDR failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << endpoint << "\n";
+		}
+		return false;
+	}
+	impl_->acceptor.set_option(opt_tcp_no_delay, ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "acceptor set option TCP_NODELAY failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << endpoint << "\n";
+		}
+		return false;
+	}
+
+	impl_->acceptor.bind(endpoint, ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "bind failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << endpoint << "\n";
+		}
+		return false;
+	}
+	return true;
+}
+
+bool CSocket::Listen(int backlog) {
+	boost::system::error_code ec;
+	impl_->acceptor.listen(backlog);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "listen failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << impl_->acceptor.local_endpoint() << "\n";
+		}
+		return false;
+	}
+	return true;
+}
+
+std::unique_ptr<CSocket> CSocket::Accept() {
+	boost::system::error_code ec;
+	auto socket = impl_->acceptor.accept(ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "accept failed: " << ec.message() << "\n";
+			std::cerr << "endpoint: " << impl_->acceptor.local_endpoint() << "\n";
+		}
+		return nullptr;
+	}
+	auto csocket = std::make_unique<CSocket>();
+	csocket->impl_ = std::make_unique<CSocketImpl>(impl_->io_context, std::move(socket));
+	return csocket;
+}
+
+bool CSocket::Connect(const std::string& host, uint16_t port) {
+	boost::system::error_code ec;
+	tcp::resolver resolver(*impl_->io_context);
+
+	auto endpoints = resolver.resolve(host, std::to_string(port), ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "resolve failed: " << ec.message() << "\n";
+		}
+		return false;
+	}
+
+	boost::asio::connect(impl_->socket, endpoints, ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "connect failed: " << ec.message() << "\n";
+		}
+		return false;
+	}
+
+	tcp::no_delay opt_tcp_no_delay(true);
+	impl_->socket.set_option(opt_tcp_no_delay, ec);
+	if (ec) {
+		if (verbose_) {
+			std::cerr << "socket set option TCP_NODELAY failed: " << ec.message() << "\n";
+		}
+		return false;
+	}
+	return true;
+}
+
+size_t CSocket::Receive(void* buf, size_t bytes) {
+	boost::system::error_code ec;
+	auto bytes_transferred =
+		boost::asio::read(impl_->socket, boost::asio::buffer(buf, bytes), ec);
+	if (ec && verbose_) {
+		std::cerr << "read failed: " << ec.message() << "\n";
+	}
+	{
+		std::lock_guard<std::mutex> lock(recv_count_mutex_);
+		recv_count_ += bytes_transferred;
+	}
+	return bytes_transferred;
+}
+
+size_t CSocket::Send(const void* buf, size_t bytes) {
+	boost::system::error_code ec;
+	auto bytes_transferred =
+		boost::asio::write(impl_->socket, boost::asio::buffer(buf, bytes), ec);
+	if (ec && verbose_) {
+		std::cerr << "write failed: " << ec.message() << "\n";
+	}
+	{
+		std::lock_guard<std::mutex> lock(send_count_mutex_);
+		send_count_ += bytes_transferred;
+	}
+	return bytes_transferred;
+}

+ 68 - 0
2p-preprocessing/ENCRYPTO_utils/socket.h

@@ -0,0 +1,68 @@
+/**
+ \file 		socket.h
+ \author 	Seung Geol Choi
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+ Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+This program 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 3 of the License, or
+(at your option) any later version.
+ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Socket Implementation
+ */
+
+#ifndef __SOCKET_H__BY_SGCHOI
+#define __SOCKET_H__BY_SGCHOI
+
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <string>
+
+
+class CSocket {
+public:
+	CSocket(bool verbose=false);
+	~CSocket();
+
+	uint64_t getSndCnt() const;
+	uint64_t getRcvCnt() const;
+	void ResetSndCnt();
+	void ResetRcvCnt();
+
+	bool Socket();
+
+	void Close();
+
+	std::string GetIP() const;
+
+	uint16_t GetPort() const;
+
+	bool Bind(const std::string& address = "", uint16_t port = 0);
+
+	bool Listen(int nQLen = 5);
+
+	std::unique_ptr<CSocket> Accept();
+
+	bool Connect(const std::string& host, uint16_t port);
+
+	size_t Receive(void* buf, size_t bytes);
+
+	size_t Send(const void* buf, size_t bytes);
+
+private:
+	struct CSocketImpl;
+	std::unique_ptr<CSocketImpl> impl_;
+	uint64_t send_count_, recv_count_;
+	mutable std::mutex send_count_mutex_;
+	mutable std::mutex recv_count_mutex_;
+	bool verbose_;
+};
+
+#endif //SOCKET_H__BY_SGCHOI
+

+ 98 - 0
2p-preprocessing/ENCRYPTO_utils/thread.cpp

@@ -0,0 +1,98 @@
+/**
+ \file 		thread.cpp
+ \author 	Seung Geol Choi
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+#include "thread.h"
+#include <cassert>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+CThread::CThread() : m_bRunning(false) {
+}
+CThread::~CThread() {
+	assert(!m_bRunning);
+}
+
+bool CThread::Start() {
+	thread_ = std::thread([this] { ThreadMain(); });
+	m_bRunning = true;
+	return true;
+}
+
+bool CThread::Wait() {
+	if (!m_bRunning)
+		return true;
+	m_bRunning = false;
+	thread_.join();
+	return true;
+}
+
+bool CThread::IsRunning() const {
+	return m_bRunning;
+}
+
+void CLock::Lock() {
+	mutex_.lock();
+}
+void CLock::Unlock() {
+	mutex_.unlock();
+}
+
+void CLock::lock() {
+	Lock();
+}
+void CLock::unlock() {
+	Unlock();
+}
+
+
+CEvent::CEvent(bool bManualReset, bool bInitialSet)
+: m_bManual(bManualReset), m_bSet(bInitialSet)
+{
+}
+
+bool CEvent::Set() {
+	std::unique_lock<std::mutex> lock(mutex_);
+	if (m_bSet)
+		return true;
+
+	m_bSet = true;
+	lock.unlock();
+	cv_.notify_one();
+	return true;
+}
+
+bool CEvent::Wait() {
+	std::unique_lock<std::mutex> lock(mutex_);
+	cv_.wait(lock, [this]{ return m_bSet; });
+
+	if (!m_bManual)
+		m_bSet = false;
+	return true;
+}
+
+bool CEvent::IsSet() const {
+	std::lock_guard<std::mutex> lock(mutex_);
+	return m_bSet;
+}
+
+bool CEvent::Reset() {
+	std::lock_guard<std::mutex> lock(mutex_);
+	m_bSet = false;
+	return true;
+}

+ 75 - 0
2p-preprocessing/ENCRYPTO_utils/thread.h

@@ -0,0 +1,75 @@
+/**
+ \file 		thread.h
+ \author 	Seung Geol Choi
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Receiver Thread Implementation
+ */
+
+#ifndef __THREAD_H__BY_SGCHOI
+#define __THREAD_H__BY_SGCHOI
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+class CThread {
+public:
+	CThread();
+	virtual ~CThread();
+
+	bool Start();
+	bool Wait();
+	bool IsRunning() const;
+
+protected:
+	virtual void ThreadMain() = 0;
+
+	bool m_bRunning;
+	std::thread thread_;
+};
+
+class CLock {
+public:
+	CLock() = default;
+	~CLock() = default;
+
+	void Lock();
+	void Unlock();
+
+	// make CLock `BasicLockable`
+	void lock();
+	void unlock();
+
+private:
+	std::mutex mutex_;
+};
+
+class CEvent {
+public:
+	CEvent(bool bManualReset=false, bool bInitialSet=false);
+	~CEvent() = default;
+
+	bool Set();
+	bool Wait();
+	bool IsSet() const;
+	bool Reset();
+
+private:
+	std::condition_variable cv_;
+	mutable std::mutex mutex_;
+	bool m_bManual;
+	bool m_bSet;
+};
+
+#endif //__THREAD_H__BY_SGCHOI

+ 124 - 0
2p-preprocessing/ENCRYPTO_utils/timer.cpp

@@ -0,0 +1,124 @@
+/**
+ \file 		timer.cpp
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		timer Implementation
+ */
+
+#include <sys/time.h>
+#include <string>
+#include <iostream>
+#include <cstdlib>
+#include <vector>
+
+#include "timer.h"
+#include "constants.h"
+#include "socket.h"
+#include "typedefs.h"
+
+
+aby_timings m_tTimes[P_LAST - P_FIRST + 1];
+aby_comm m_tSend[P_LAST - P_FIRST + 1];
+aby_comm m_tRecv[P_LAST - P_FIRST + 1];
+
+double getMillies(timespec timestart, timespec timeend) {
+	long time1 = (timestart.tv_sec * 1000000) + (timestart.tv_nsec / 1000);
+	long time2 = (timeend.tv_sec * 1000000) + (timeend.tv_nsec / 1000);
+
+	return (double) (time2 - time1) / 1000;
+}
+
+void StartWatch(const std::string& msg, ABYPHASE phase) {
+	if (phase < P_FIRST || phase > P_LAST) {
+		std::cerr << "Phase not recognized: " << phase << std::endl;
+		return;
+	}
+
+	clock_gettime(CLOCK_MONOTONIC, &(m_tTimes[phase].tbegin));
+#ifndef BATCH
+	std::cout << msg << std::endl;
+#else
+	(void)msg;  // silence -Wunused-parameter warning
+#endif
+}
+
+
+void StopWatch(const std::string& msg, ABYPHASE phase) {
+	if (phase < P_FIRST || phase > P_LAST) {
+		std::cerr << "Phase not recognized: " << phase << std::endl;
+		return;
+	}
+
+	clock_gettime(CLOCK_MONOTONIC, &(m_tTimes[phase].tend));
+	m_tTimes[phase].timing = getMillies(m_tTimes[phase].tbegin, m_tTimes[phase].tend);
+
+#ifndef BATCH
+	std::cout << msg << m_tTimes[phase].timing << " ms " << std::endl;
+#else
+	(void)msg;  // silence -Wunused-parameter warning
+#endif
+}
+
+void StartRecording(const std::string& msg, ABYPHASE phase,
+		const std::vector<std::unique_ptr<CSocket>>& sock) {
+	StartWatch(msg, phase);
+
+	m_tSend[phase].cbegin = 0;
+	m_tRecv[phase].cbegin = 0;
+	for(uint32_t i = 0; i < sock.size(); i++) {
+		m_tSend[phase].cbegin += sock[i]->getSndCnt();
+		m_tRecv[phase].cbegin += sock[i]->getRcvCnt();
+	}
+}
+
+void StopRecording(const std::string& msg, ABYPHASE phase,
+		const std::vector<std::unique_ptr<CSocket>>& sock) {
+	StopWatch(msg, phase);
+
+	m_tSend[phase].cend = 0;
+	m_tRecv[phase].cend = 0;
+	for(uint32_t i = 0; i < sock.size(); i++) {
+		m_tSend[phase].cend += sock[i]->getSndCnt();
+		m_tRecv[phase].cend += sock[i]->getRcvCnt();
+	}
+
+	m_tSend[phase].totalcomm = m_tSend[phase].cend - m_tSend[phase].cbegin;
+	m_tRecv[phase].totalcomm = m_tRecv[phase].cend - m_tRecv[phase].cbegin;
+}
+
+
+void PrintTimings() {
+	std::string unit = " ms";
+	std::cout << "Timings: " << std::endl;
+	std::cout << "Total =\t\t" << m_tTimes[P_TOTAL].timing << unit << std::endl;
+	std::cout << "Init =\t\t" << m_tTimes[P_INIT].timing << unit << std::endl;
+	std::cout << "CircuitGen =\t" << m_tTimes[P_CIRCUIT].timing << unit << std::endl;
+	std::cout << "Network =\t" << m_tTimes[P_NETWORK].timing << unit << std::endl;
+	std::cout << "BaseOTs =\t" << m_tTimes[P_BASE_OT].timing << unit << std::endl;
+	std::cout << "Setup =\t\t" << m_tTimes[P_SETUP].timing << unit << std::endl;
+	std::cout << "OTExtension =\t" << m_tTimes[P_OT_EXT].timing << unit << std::endl;
+	std::cout << "Garbling =\t" << m_tTimes[P_GARBLE].timing << unit << std::endl;
+	std::cout << "Online =\t" << m_tTimes[P_ONLINE].timing << unit << std::endl;
+}
+
+void PrintCommunication() {
+	std::string unit = " bytes";
+	std::cout << "Communication: " << std::endl;
+	std::cout << "Total Sent / Rcv\t" << m_tSend[P_TOTAL].totalcomm << " " << unit << " / " << m_tRecv[P_TOTAL].totalcomm << unit << std::endl;
+	std::cout << "BaseOTs Sent / Rcv\t" << m_tSend[P_BASE_OT].totalcomm << " " << unit << " / " << m_tRecv[P_BASE_OT].totalcomm << unit << std::endl;
+	std::cout << "Setup Sent / Rcv\t" << m_tSend[P_SETUP].totalcomm << " " << unit << " / " << m_tRecv[P_SETUP].totalcomm << unit << std::endl;
+	std::cout << "OTExtension Sent / Rcv\t" << m_tSend[P_OT_EXT].totalcomm << " " << unit << " / " << m_tRecv[P_OT_EXT].totalcomm << unit << std::endl;
+	std::cout << "Garbling Sent / Rcv\t" << m_tSend[P_GARBLE].totalcomm << " " << unit << " / " << m_tRecv[P_GARBLE].totalcomm << unit << std::endl;
+	std::cout << "Online Sent / Rcv\t" << m_tSend[P_ONLINE].totalcomm << " " << unit << " / " << m_tRecv[P_ONLINE].totalcomm << unit << std::endl;
+}

+ 107 - 0
2p-preprocessing/ENCRYPTO_utils/timer.h

@@ -0,0 +1,107 @@
+/**
+ \file 		timer.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		timer Implementation
+ */
+
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+class CSocket;
+
+//Note do not change P_FIRST and P_LAST and keep them pointing to the first and last element in the enum
+enum ABYPHASE {
+	P_TOTAL, P_INIT, P_CIRCUIT, P_NETWORK, P_BASE_OT, P_SETUP, P_OT_EXT, P_GARBLE, P_ONLINE, P_FIRST = P_TOTAL, P_LAST = P_ONLINE
+};
+
+// Structure for measuring runtime
+struct aby_timings {
+	double timing;
+	timespec tbegin;
+	timespec tend;
+};
+
+// Structure for counting communication
+struct aby_comm {
+	uint64_t totalcomm;
+	uint64_t cbegin;
+	uint64_t cend;
+};
+
+extern aby_timings m_tTimes[P_LAST - P_FIRST + 1];
+extern aby_comm m_tSend[P_LAST - P_FIRST + 1];
+extern aby_comm m_tRecv[P_LAST - P_FIRST + 1];
+
+/**
+ * Return time difference in milliseconds
+ */
+double getMillies(timespec timestart, timespec timeend);
+
+/**
+ * Start measuring runtime for a given phase
+ * @param msg - a message for debugging
+ * @param phase - the ABY phase to measure
+ */
+void StartWatch(const std::string& msg, ABYPHASE phase);
+
+/**
+ * Stop measuring runtime
+ * Called after StartWatch() with identical phase parameter
+ * @param msg - a message for debugging
+ * @param phase - the ABY phase to measure
+ */
+void StopWatch(const std::string& msg, ABYPHASE phase);
+
+/**
+ * Start measuring both runtime and communication
+ * @param msg - a message for debugging
+ * @param phase - the ABY phase to measure
+ * @param sock - a vector of sockets
+ */
+void StartRecording(const std::string& msg, ABYPHASE phase,
+		const std::vector<std::unique_ptr<CSocket>>& sock);
+
+/**
+ * Stop measuring both runtime and communication
+ * Called after StartRecording() with identical phase parameter
+ * @param msg - a message for debugging
+ * @param phase - the ABY phase to measure
+ * @param sock - a vector of sockets
+ */
+void StopRecording(const std::string& msg, ABYPHASE phase,
+		const std::vector<std::unique_ptr<CSocket>>& sock);
+
+void PrintTimings();
+
+void PrintCommunication();
+
+inline double GetTimeForPhase(ABYPHASE phase) {
+	return m_tTimes[phase].timing;
+}
+
+inline uint64_t GetSentDataForPhase(ABYPHASE phase) {
+	return m_tSend[phase].totalcomm;
+}
+
+inline uint64_t GetReceivedDataForPhase(ABYPHASE phase) {
+	return m_tRecv[phase].totalcomm;
+}
+
+#endif /* TIMER_H_ */

+ 77 - 0
2p-preprocessing/ENCRYPTO_utils/typedefs.h

@@ -0,0 +1,77 @@
+/**
+ \file 		typedefs.h
+ \author 	michael.zohner@ec-spride.de
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		Typedefs Implementation
+ */
+
+#ifndef __TYPEDEFS_H__
+#define __TYPEDEFS_H__
+
+#include <cstdint>
+
+typedef int BOOL;
+typedef unsigned char BYTE;
+
+typedef uint64_t UGATE_T;
+typedef uint64_t REGISTER_SIZE;
+
+typedef struct SECURITYLEVELS {
+	uint32_t statbits;
+	uint32_t symbits;
+	uint32_t ifcbits;
+	//ECCLVL depends on CMAKE settings
+} seclvl;
+
+//ECCLVL depends on CMAKE settings
+
+#define GATE_T_BITS (sizeof(UGATE_T) * 8)
+
+typedef REGISTER_SIZE REGSIZE;
+#define LOG2_REGISTER_SIZE		ceil_log2(sizeof(REGISTER_SIZE) << 3)
+
+#define FILL_BYTES				AES_BYTES
+#define FILL_BITS				AES_BITS
+
+#define RETRY_CONNECT		1000
+#define CONNECT_TIMEO_MILISEC	10000
+
+#define SNDVALS 2
+
+#define OTEXT_BLOCK_SIZE_BITS	AES_BITS
+#define OTEXT_BLOCK_SIZE_BYTES	AES_BYTES
+
+#define VECTOR_INTERNAL_SIZE 8
+
+#define	SERVER_ID	0
+#define	CLIENT_ID	1
+
+template<class T>
+T rem(T a, T b) {
+	return ((a) > 0) ? (a) % (b) : (a) % (b) + ((b) > 0 ? (b) : (b) * -1);
+}
+template<class T>
+T sub(T a, T b, T m) {
+	return ((b) > (a)) ? (a) + (m) - (b) : (a) - (b);
+}
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#define ZERO_BYTE 0
+#define MAX_BYTE 0xFF
+
+#endif //__TYPEDEFS_H__

+ 125 - 0
2p-preprocessing/ENCRYPTO_utils/utils.cpp

@@ -0,0 +1,125 @@
+/**
+ \file 		utils.cpp
+ \author 	
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		utils
+ */
+
+#include "utils.h"
+
+#include <cstdint>
+#include <fcntl.h>
+#include <gmp.h>
+#include <iostream>
+#include <unistd.h>
+
+
+//TODO: this is bad, fix occurrences of ceil_log2 and replace by ceil_log2_min1 where log(1) = 1 is necessary. For all else use ceil_log2_real
+uint32_t ceil_log2(int bits) {
+	if (bits == 1)
+		return 1;
+	int targetlevel = 0, bitstemp = bits;
+	while (bitstemp >>= 1)
+		++targetlevel;
+	return targetlevel + ((1 << targetlevel) < bits);
+}
+
+uint32_t ceil_log2_min1(int bits) {
+	if (bits <= 1)
+		return 1;
+	int targetlevel = 0, bitstemp = bits;
+	while (bitstemp >>= 1)
+		++targetlevel;
+	return targetlevel + ((1 << targetlevel) < bits);
+}
+
+uint32_t ceil_log2_real(int bits) {
+	if (bits == 1)
+		return 0;
+	int targetlevel = 0, bitstemp = bits;
+	while (bitstemp >>= 1)
+		++targetlevel;
+	return targetlevel + ((1 << targetlevel) < bits);
+}
+
+uint32_t floor_log2(int bits) {
+	if (bits == 1)
+		return 1;
+	int targetlevel = 0;
+	while (bits >>= 1)
+		++targetlevel;
+	return targetlevel;
+}
+
+/**
+ * returns a 4-byte value from dev/random
+ */
+uint32_t aby_rand() {
+	int frandom = open("/dev/random", O_RDONLY);
+	if (frandom < 0) {
+		std::cerr << "Error in opening /dev/random: utils.h:aby_rand()" << std::endl;
+		exit(1);
+	} else {
+		char data[4];
+		size_t len = 0;
+		while (len < sizeof data) {
+			ssize_t result = read(frandom, data + len, (sizeof data) - len);
+			if (result < 0) {
+				std::cerr << "Error in generating random number: utils.h:aby_rand()" << std::endl;
+				exit(1);
+			}
+			len += result;
+		}
+		close(frandom);
+		return *((uint32_t*) data);
+	}
+	return 0;
+}
+
+/**
+ * returns a random mpz_t with bitlen len generated from dev/urandom
+ */
+void aby_prng(mpz_t rnd, mp_bitcnt_t bitlen) {
+	size_t byte_count = ceil_divide(bitlen, 8);
+	char * data;
+
+	int furandom = open("/dev/urandom", O_RDONLY);
+	if (furandom < 0) {
+		std::cerr << "Error in opening /dev/urandom: utils.cpp:aby_prng()" << std::endl;
+		exit(1);
+	} else {
+		data = (char*) malloc(sizeof(*data) * byte_count);
+		size_t len = 0;
+		while (len < byte_count) {
+			ssize_t result = read(furandom, data + len, byte_count - len);
+			if (result < 0) {
+				std::cerr << "Error in generating random number: utils.cpp:aby_prng()" << std::endl;
+				exit(1);
+			}
+			len += result;
+		}
+		close(furandom);
+	}
+
+    mpz_import(rnd, byte_count, 1, sizeof(*data), 0, 0, data);
+
+    //set MSBs to zero, if we are not working on full bytes
+    if (bitlen % 8) {
+      for (uint8_t i = 0; i < 8 - bitlen % 8; ++i) {
+        mpz_clrbit(rnd, byte_count * 8 - i - 1);
+      }
+    }
+
+    free(data);
+}

+ 66 - 0
2p-preprocessing/ENCRYPTO_utils/utils.h

@@ -0,0 +1,66 @@
+/**
+ \file 		utils.h
+ \author 	
+ \copyright	ABY - A Framework for Efficient Mixed-protocol Secure Two-party Computation
+			Copyright (C) 2019 ENCRYPTO Group, TU Darmstadt
+			This program 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 3 of the License, or
+            (at your option) any later version.
+            ABY 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 program. If not, see <http://www.gnu.org/licenses/>.
+ \brief		utils
+ */
+
+#ifndef _UTILS_H__
+#define _UTILS_H__
+
+#include <cstdint>
+#include <gmp.h>
+#include <unistd.h>
+
+#ifdef WIN32
+#define SleepMiliSec(x)	Sleep(x)
+#else
+#define SleepMiliSec(x)			usleep((x)<<10)
+#endif
+
+#define two_pow(e) (((uint64_t) 1) << (e))
+
+#define pad_to_power_of_two(e) ( ((uint64_t) 1) << (ceil_log2(e)) )
+
+/*compute (a-b) mod (m+1) as: b > a ? (m) - (b-1) + a : a - b	*/
+#define MOD_SUB(a, b, m) (( ((b) > (a))? (m) - ((b) -1 ) + a : a - b))
+
+#define ceil_divide(x, y)			(( ((x) + (y)-1)/(y)))
+#define bits_in_bytes(bits) (ceil_divide((bits), 8))
+#define pad_to_multiple(x, y) 		( ceil_divide(x, y) * (y))
+
+#define PadToRegisterSize(x) 		(PadToMultiple(x, OTEXT_BLOCK_SIZE_BITS))
+#define PadToMultiple(x, y) 		( ceil_divide(x, y) * (y))
+
+//TODO: this is bad, fix occurrences of ceil_log2 and replace by ceil_log2_min1 where log(1) = 1 is necessary. For all else use ceil_log2_real
+uint32_t ceil_log2(int bits);
+
+uint32_t ceil_log2_min1(int bits);
+
+uint32_t ceil_log2_real(int bits);
+
+uint32_t floor_log2(int bits);
+
+/**
+ * returns a 4-byte value from dev/random
+ */
+uint32_t aby_rand();
+
+/**
+ * returns a random mpz_t with bitlen len generated from dev/urandom
+ */
+void aby_prng(mpz_t rnd, mp_bitcnt_t len);
+
+
+#endif // _UTILS_H__

+ 48 - 0
2p-preprocessing/Makefile

@@ -0,0 +1,48 @@
+default: build preprocessing0 preprocessing1 
+
+build: ot_blinds.cpp ot_blinds.h
+	g++ -DECCLVL=251 -I ~/OTExtension/extern/ENCRYPTO_utils/src/ -I ~/OTExtension/ -O3 -DNDEBUG -std=gnu++17 -o ot_blinds.cpp.o -c ot_blinds.cpp
+	g++ -O3 -DNDEBUG ot_blinds.cpp.o -o OT external/libaby.a external/libencrypto_utils.a -lstdc++fs external/libotextension.a external/libencrypto_utils.a external/librelic_s.a -lpthread -l boost_system -l boost_thread -l gmp -l gmpxx -l crypto
+
+debug: ot_blinds.cpp ot_blinds.h
+	g++ -DECCLVL=251 -I ~/OTExtension/extern/ENCRYPTO_utils/src/ -I ~/OTExtension/ -O3 -g -std=gnu++17 -o ot_blinds.cpp.o -c ot_blinds.cpp
+	g++ -O3 -g ot_blinds.cpp.o -o OT external/libaby.a external/libencrypto_utils.a -lstdc++fs external/libotextension.a external/libencrypto_utils.a external/librelic_s.a -lpthread -l boost_system -l boost_thread -l gmp -l gmpxx -l crypto
+
+#clean:
+#	rm ot_blinds.cpp.o
+#	rm OT
+
+CXX = g++
+CXXFLAGS = -g -march=native -std=c++17 -Wall -pedantic -fopenmp -O3 -Wno-ignored-attributes -pthread
+LIBS = -lbsd -lboost_system -lboost_thread -pthread
+FLAGS = -DDEBUG -DBOOST_ERROR_CODE_HEADER_ONLY 
+
+# OPENSSL_INCLUDE ?= -I/usr/include/openssl
+# CXXFLAGS += $(OPENSSL_INCLUDE)
+# OPENSSL_LIBS ?= -lcrypto
+# LIBS += $(OPENSSL_LIBS)
+
+#BINDIR = bin 
+
+all: directories preprocessing0 preprocessing1 
+ 
+preprocessing0: preprocessing.cpp  #dpf++/dpf.h  
+	$(CXX) $(CXXFLAGS) -o preprocessing0 preprocessing.cpp $(LIBS) $(FLAGS) -DPARTY=0 -I.
+
+preprocessing1: preprocessing.cpp #dpf++/dpf.h 
+	$(CXX) $(CXXFLAGS) -o preprocessing1 preprocessing.cpp $(LIBS) $(FLAGS) -DPARTY=1 -I.
+
+docs:
+	doxygen Doxyfile
+
+.PHONY: directories
+
+directories: $(BINDIR)
+
+# $(BINDIR):
+# 	mkdir -p $(BINDIR)
+
+clean:
+	rm -f preprocessing1 preprocessing0
+	rm ot_blinds.cpp.o
+	rm OT

+ 1 - 0
2p-preprocessing/X0.txt

@@ -0,0 +1 @@
+1101110011110010101110011110110101110011101110000010101101100111010110101101000111101111010011001001010100001110001101001111010001011000010111010101010010000110001001110100101111111101001111010000001111000100010011000101111010010001001111100011100111010011

+ 1 - 0
2p-preprocessing/X1.txt

@@ -0,0 +1 @@
+1011010010010001000100001011000010000011111110001101000000011011111000110000111111001001100010111011000000011011111111011010011011100001101100001110110011011110111111111001000010011101011010100110001000100001100001110110110010111100011101100000101010011010

+ 1 - 0
2p-preprocessing/Y0.txt

@@ -0,0 +1 @@
+1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

+ 1 - 0
2p-preprocessing/Y1.txt

@@ -0,0 +1 @@
+1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

+ 152 - 0
2p-preprocessing/aes.h

@@ -0,0 +1,152 @@
+/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
+/* ====================================================================
+ * Copyright (c) 1998-2002 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.
+ * ====================================================================
+ *
+ */
+
+
+#ifndef DPFPP_AES_H
+#define DPFPP_AES_H
+
+#include <x86intrin.h>
+#define EXPAND_ASSIST(v1,v2,v3,v4,shuff_const,aes_const)                    \
+    v2 = _mm_aeskeygenassist_si128(v4,aes_const);                           \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3),              \
+                                         _mm_castsi128_ps(v1), 16));        \
+    v1 = _mm_xor_si128(v1,v3);                                              \
+    v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3),              \
+                                         _mm_castsi128_ps(v1), 140));       \
+    v1 = _mm_xor_si128(v1,v3);                                              \
+    v2 = _mm_shuffle_epi32(v2,shuff_const);                                 \
+    v1 = _mm_xor_si128(v1,v2)
+
+struct AES_KEY
+{
+    AES_KEY(const __m128i userkey = _mm_set_epi64x(597349, 121379))
+      : rounds(10)
+    {
+        __m128i x0, x1, x2;
+        rd_key[0] = x0 = userkey;
+        x2 = _mm_setzero_si128();
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 1);
+        rd_key[1] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 2);
+        rd_key[2] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 4);
+        rd_key[3] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 8);
+        rd_key[4] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 16);
+        rd_key[5] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 32);
+        rd_key[6] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 64);
+        rd_key[7] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 128);
+        rd_key[8] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 27);
+        rd_key[9] = x0;
+        EXPAND_ASSIST(x0, x1, x2, x0, 255, 54);
+        rd_key[10] = x0;
+    }
+    __m128i rd_key[11];
+    unsigned int rounds;
+} ;
+
+static const AES_KEY default_aes_key;
+
+static inline void
+AES_ecb_encrypt_blks(__m128i * __restrict__ blks, unsigned int nblks, const AES_KEY * __restrict__ key)
+{
+    for (unsigned int i = 0; i < nblks; ++i)
+        blks[i] = _mm_xor_si128(blks[i], key->rd_key[0]);
+    for (unsigned int j = 1; j < key->rounds; ++j)
+        for (unsigned int i = 0; i < nblks; ++i)
+            blks[i] = _mm_aesenc_si128(blks[i], key->rd_key[j]);
+    for (unsigned int i = 0; i < nblks; ++i)
+        blks[i] = _mm_aesenclast_si128(blks[i], key->rd_key[key->rounds]);
+}
+
+static inline void
+AES_set_decrypt_key_fast(AES_KEY * __restrict__ dkey, const AES_KEY * __restrict__ ekey)
+{
+    int j = 0;
+    int i = ekey->rounds;
+#if (OCB_KEY_LEN == 0)
+    dkey->rounds = i;
+#endif
+    dkey->rd_key[i--] = ekey->rd_key[j++];
+    while (i)
+        dkey->rd_key[i--] = _mm_aesimc_si128(ekey->rd_key[j++]);
+    dkey->rd_key[i] = ekey->rd_key[j];
+}
+
+/*
+static inline void
+AES_set_decrypt_key(__m128i userkey, AES_KEY * __restrict__ key)
+{
+    AES_KEY temp_key;
+    AES_set_encrypt_key(userkey, &temp_key);
+    AES_set_decrypt_key_fast(key, &temp_key);
+}
+*/
+
+static inline void
+AES_ecb_decrypt_blks(__m128i * __restrict__ blks, unsigned nblks, const AES_KEY * __restrict__ key)
+{
+    unsigned i, j, rnds = key->rounds;
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_xor_si128(blks[i], key->rd_key[0]);
+    for (j = 1; j < rnds; ++j)
+        for (i = 0; i < nblks; ++i)
+            blks[i] = _mm_aesdec_si128(blks[i], key->rd_key[j]);
+    for (i = 0; i < nblks; ++i)
+        blks[i] = _mm_aesdeclast_si128(blks[i], key->rd_key[j]);
+}
+
+#endif

+ 202 - 0
2p-preprocessing/bitutils.h

@@ -0,0 +1,202 @@
+/* Copyright (C) 2019  Anonymous
+ *
+ * This is a pre-release version of the DPF++ library distributed anonymously
+ * for peer review. A public release of the software will be published under the
+ * LPGL v2.1 license in the near future. Please do not redistribute this version
+ * of the software.
+ */
+
+#ifndef DPF_BITUTILS_H__
+#define DPF_BITUTILS_H__
+
+#include <bitset>       // std::bitset
+
+#include <x86intrin.h>  // SSE and AVX intrinsics
+
+namespace dpf
+{
+
+static const __m128i bool128_mask[2] = {
+	_mm_set_epi64x(0,1),                                        // 0b00...0001
+	_mm_set_epi64x(1,0)                                         // 0b00...0001 << 64
+};
+static const __m256i bool256_mask[4] = {
+	_mm256_set_epi64x(0,0,0,1),                                 // 0b00...0001
+	_mm256_set_epi64x(0,0,1,0),                                 // 0b00...0001 << 64
+	_mm256_set_epi64x(0,1,0,0),                                 // 0b00...0001 << 128
+	_mm256_set_epi64x(1,0,0,0)                                  // 0b00...0001 << 192
+};
+
+static const __m128i lsb128_mask[4] = {
+	_mm_setzero_si128(),                                        // 0b00...0000
+	_mm_set_epi64x(0,1),                                        // 0b00...0001
+	_mm_set_epi64x(0,2),                                        // 0b00...0010
+	_mm_set_epi64x(0,3)                                         // 0b00...0011
+};
+static const __m128i lsb128_mask_inv[4] = {
+	_mm_set1_epi8(-1),                                          // 0b11...1111
+	_mm_set_epi64x(-1,-2),                                      // 0b11...1110
+	_mm_set_epi64x(-1,-3),                                      // 0b11...1101
+	_mm_set_epi64x(-1,-4)                                       // 0b11...1100
+};
+static const __m128i if128_mask[2] = {
+	_mm_setzero_si128(),                                        // 0b00...0000
+	_mm_set1_epi8(-1)                                           // 0b11...1111
+};
+
+static const __m256i lsb256_mask[4] = {
+	_mm256_setzero_si256(),                                     // 0b00...0000
+	_mm256_set_epi64x(0,0,0,1),                                 // 0b00...0001
+	_mm256_set_epi64x(0,0,0,2),                                 // 0b00...0010
+	_mm256_set_epi64x(0,0,0,3)                                  // 0b00...0011
+};
+static const __m256i lsb256_mask_inv[4] = {
+	_mm256_set1_epi8(-1),                                       // 0b11...1111
+	_mm256_set_epi64x(-1,-1,-1,-2),                             // 0b11...1110
+	_mm256_set_epi64x(-1,-1,-1,-3),                             // 0b11...1101
+	_mm256_set_epi64x(-1,-1,-1,-4)                              // 0b11...1100
+};
+static const __m256i if256_mask[2] = {
+	_mm256_setzero_si256(),                                     // 0b00...0000
+	_mm256_set1_epi8(-1)                                        // 0b11...1111
+};
+inline __m128i xor_if(const __m128i & block1, const __m128i & block2, __m128i flag)
+{
+ return _mm_xor_si128(block1, _mm_and_si128(block2, flag));
+}
+
+ inline __m256i xor_if(const __m256i & block1, const __m256i & block2, __m256i flag)
+{
+ return _mm256_xor_si256(block1, _mm256_and_si256(block2, flag));
+}
+
+inline __m128i xor_if(const __m128i & block1, const __m128i & block2, bool flag)
+{
+	return _mm_xor_si128(block1, _mm_and_si128(block2, if128_mask[flag ? 1 : 0]));
+}
+inline __m256i xor_if(const __m256i & block1, const __m256i & block2, bool flag)
+{
+	return _mm256_xor_si256(block1, _mm256_and_si256(block2, if256_mask[flag ? 1 : 0]));
+}
+
+inline uint8_t get_lsb(const __m128i & block, uint8_t bits = 0b01)
+{
+	__m128i vcmp = _mm_xor_si128(_mm_and_si128(block, lsb128_mask[bits]), lsb128_mask[bits]);
+	return static_cast<uint8_t>(_mm_testz_si128(vcmp, vcmp));
+}
+inline uint8_t get_lsb(const __m256i & block, uint8_t bits = 0b01)
+{
+	__m256i vcmp = _mm256_xor_si256(_mm256_and_si256(block, lsb256_mask[bits]), lsb256_mask[bits]);
+	return static_cast<uint8_t>(_mm256_testz_si256(vcmp, vcmp));
+}
+template <typename __mX>
+inline uint8_t get_lsb01(const __mX & block) { return get_lsb(block, 0b01); }
+template <typename __mX>
+inline uint8_t get_lsb10(const __mX & block) { return get_lsb(block, 0b10); }
+
+
+inline __m128i clear_lsb(const __m128i & block, uint8_t bits = 0b01)
+{
+	return _mm_and_si128(block, lsb128_mask_inv[bits]);
+}
+inline __m256i clear_lsb(const __m256i & block, uint8_t bits = 0b01)
+{
+	return _mm256_and_si256(block, lsb256_mask_inv[bits]);
+}
+
+// template<typename row_t = __m256i >	
+// inline std::array<row_t, 128> bitsliced_clear_lsb(std::array<row_t, 128>& block, uint8_t bits = 0b11)
+// {
+// 	if(bits == 0b11)
+// 	{
+// 	 block[0] = _mm_set_epi64x(0, 0); 
+// 	 block[1] = _mm_set_epi64x(0, 0); 
+// 	}
+// 	if(bits == 0b01)
+// 	{
+// 	  block[0] = _mm_set_epi64x(0, 0); 
+// 	}
+// 	return block;
+// }
+
+template<typename row_t = __m256i, size_t nrows >	
+inline row_t bitslicled_get_lsb(std::array<row_t, nrows> block, uint8_t bit = 0b01)
+{	
+	if(bit == 0b01)	
+	{
+	 return block[0];
+	}
+	else if (bit == 0b10)
+	{
+	 return block[1];
+	}
+	else
+	{
+      return block[0];
+	}
+}
+
+template <typename __mX>
+inline __mX clear_lsb01(const __mX & block) { return clear_lsb(block, 0b01); }
+template <typename __mX>
+inline __mX clear_lsb10(const __mX & block) { return clear_lsb(block, 0b10); }
+template <typename __mX>
+inline __mX clear_lsb11(const __mX & block) { return clear_lsb(block, 0b11); }
+
+
+inline void set_ones(__m128i & input)
+{
+	input = _mm_set1_epi64x(-1);
+}
+
+inline void set_ones(__m256i & input)
+{
+	input = _mm256_set1_epi64x(-1);
+}
+
+
+
+inline void set_zeros(__m128i & input)
+{
+	input = _mm_setzero_si128();
+}
+
+inline void set_zeros(__m256i & input)
+{
+	input = _mm256_setzero_si256();
+}
+
+// inline void zeros(block<__m128i> & input)
+// {
+// 	input = _mm_setzero_si128();
+// }
+
+// inline void zeros(block<__m256i> & input)
+// {
+// 	input = _mm256_setzero_si256();
+// }
+
+
+inline __m128i set_lsb(const __m128i & block, const bool val = true)
+{
+	return _mm_or_si128(clear_lsb(block, 0b01), lsb128_mask[val ? 0b01 : 0b00]);
+}
+inline __m256i set_lsb(const __m256i & block, const bool val = true)
+{
+	return _mm256_or_si256(clear_lsb(block, 0b01), lsb256_mask[val ? 0b01 : 0b00]);;
+}
+
+inline __m128i set_lsbs(const __m128i & block, const bool bits[2])
+{
+	int i = (bits[0] ? 1 : 0) + 2 * (bits[1] ? 1 : 0);
+	return _mm_or_si128(clear_lsb(block, 0b11), lsb128_mask[i]);
+}
+inline __m256i set_lsbs(const __m256i & block, const bool bits[2])
+{
+	int i = (bits[0] ? 1 : 0) + 2 * (bits[1] ? 1 : 0);
+	return _mm256_or_si256(clear_lsb(block, 0b11), lsb256_mask[i]);
+}
+
+} // namespace lowmc
+
+#endif // DPF_BITUTILS_H__

+ 185 - 0
2p-preprocessing/block.h

@@ -0,0 +1,185 @@
+/**  
+ *  
+ *  @license GNU Public License (version 2); see LICENSE for full license text
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program 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 General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ **/
+
+#ifndef LOWMC_BLOCK_H__
+#define LOWMC_BLOCK_H__
+
+#include <bitset>       // std::bitset
+#include <string>       // std::string
+#include <iostream>     // std::istream and std::ostream
+
+#include <x86intrin.h>  // SSE and AVX intrinsics
+
+// namespace lowmc
+// {
+
+template <typename __mX>
+union block
+{
+  public:
+	typedef __mX value_type;
+
+	block(const uint64_t input = 0ULL) : bits(input) { }
+	block(const __mX & val) : mX(val) { }
+	block(const std::string bit_string) : bits(bit_string) { }
+	inline operator __mX() const { return mX; }
+	inline block<__mX> & operator=(const __mX & val) { mX = val; return *this; }
+	inline bool operator==(const __mX & rhs) const;
+	inline bool operator!=(const __mX & rhs) const { return !(*this == rhs); }
+	inline typename std::bitset<sizeof(__mX) * 8>::reference operator[](const size_t pos) { return bits[pos]; }
+	inline const bool operator[](const size_t pos) const { return bits[pos]; }
+	constexpr inline size_t size() const { return sizeof(__mX) * 8; }
+	inline const unsigned parity() const { return bits.count() % 2; }
+	inline void shiftr(const size_t pos) { bits >>= pos; }
+ 	inline void shiftl(const size_t pos) { bits <<= pos; }
+	std::bitset<8 * sizeof(__mX)> bits;
+  //private:
+	block(std::bitset<8 * sizeof(__mX)> & bitset) : bits(bitset) { }
+	__mX mX;
+	
+};
+
+template<>
+inline bool block<__m128i>::operator==(const __m128i & rhs) const
+{
+	auto vcmp = _mm_xor_si128(*this, rhs);
+	return _mm_testz_si128(vcmp, vcmp);
+}
+template<>
+inline bool block<__m256i>::operator==(const __m256i & rhs) const
+{
+	auto vcmp = _mm256_xor_si256(*this, rhs);
+	return _mm256_testz_si256(vcmp, vcmp);
+}
+ 
+template<typename __mX>
+inline block<__mX> operator|(const block<__mX> & block1, const block<__mX> & block2);
+ 
+template<>
+inline block<__m256i> operator|(const block<__m256i> & block1, const block<__m256i> & block2)
+{
+	return _mm256_or_si256(block1, block2);
+}
+template<>
+inline block<__m128i> operator|(const block<__m128i> & block1, const block<__m128i> & block2)
+{
+	return _mm_or_si128(block1, block2);
+}
+
+template<typename __mX>
+inline block<__mX> operator&(const block<__mX> & block1, const block<__mX> & block2);
+ 
+template<>
+inline block<__m256i> operator&(const block<__m256i> & block1, const block<__m256i> & block2)
+{
+	return _mm256_and_si256(block1, block2);
+}
+template<>
+inline block<__m128i> operator&(const block<__m128i> & block1, const block<__m128i> & block2)
+{
+	return _mm_and_si128(block1, block2);
+}
+
+template<typename __mX>
+inline block<__mX> operator^(const block<__mX> & block1, const block<__mX> & block2);
+ 
+template<>
+inline block<__m256i> operator^(const block<__m256i> & block1, const block<__m256i> & block2)
+{
+	return _mm256_xor_si256(block1, block2);
+}
+
+template<>
+inline block<__m128i> operator^(const block<__m128i> & block1, const block<__m128i> & block2)
+{
+	return _mm_xor_si128(block1, block2);
+}
+
+template<typename __mX>
+inline block<__mX> & operator^=(block<__mX> & block1, const block<__mX> & block2);
+ 
+template<>
+inline block<__m256i> & operator^=(block<__m256i> & block1, const block<__m256i> & block2)
+{
+	block1 = _mm256_xor_si256(block1, block2);
+	return block1;
+}
+template<>
+inline block<__m128i> & operator^=(block<__m128i> & block1, const block<__m128i> & block2)
+{
+	block1 = _mm_xor_si128(block1, block2);
+	return block1;
+}
+
+
+template<typename __mX>
+inline block<__mX> operator~(const block<__mX> & block);
+ 
+template<>
+inline block<__m256i> operator~(const block<__m256i> & block)
+{
+	return ~static_cast<__m256i>(block);
+}
+template<>
+inline block<__m128i> operator~(const block<__m128i> & block)
+{
+	return ~static_cast<__m128i>(block);
+}
+
+template<typename __mX>
+inline block<__mX> operator<<(const block<__mX> & block, const long & shift);
+template<>
+inline block<__m256i> operator<<(const block<__m256i> & block , const long & shift)
+{
+	return _mm256_or_si256(_mm256_slli_epi64(block, shift), _mm256_blend_epi32(_mm256_setzero_si256(), _mm256_permute4x64_epi64(_mm256_srli_epi64(block, 64 - shift), _MM_SHUFFLE(2,1,0,0)), _MM_SHUFFLE(3,3,3,0)));
+}
+template<>
+inline block<__m128i> operator<<(const block<__m128i> & block, const long & shift)
+{
+  return _mm_or_si128(_mm_slli_epi64(block, shift), _mm_srli_epi64(_mm_slli_si128(block, 8), 64 - shift));
+}
+template<typename __mX>
+inline block<__mX> & operator<<=(block<__mX> & block, const long & shift)
+{
+	block = block << shift;
+	return block;
+}
+
+template<typename __mX>
+inline block<__mX> operator>>(const block<__mX> & block, const long & shift);
+template<>
+inline block<__m256i> operator>>(const block<__m256i> & block, const long & shift)
+{
+	return _mm256_or_si256(_mm256_srli_epi64(block, shift), _mm256_blend_epi32(_mm256_setzero_si256(), _mm256_permute4x64_epi64(_mm256_slli_epi64(block, 64 - shift), _MM_SHUFFLE(0,3,2,1)), _MM_SHUFFLE(0,3,3,3)));
+}
+template<>
+inline block<__m128i> operator>>(const block<__m128i> & block, const long & shift)
+{
+	return _mm_or_si128(_mm_srli_epi64(block, shift), _mm_slli_epi64(_mm_srli_si128(block, 8), 64 - shift));
+}
+template<typename __mX>
+inline block<__mX> & operator>>=(block<__mX> & block, const long & shift)
+{
+	block = block >> shift;
+	return block;
+}
+
+//} // namespace lowmc
+
+#endif // LOWMC_BLOCK_H__

+ 1 - 0
2p-preprocessing/gamma0.txt

@@ -0,0 +1 @@
+1110110110001001110110100000100110011101010001100011011010011100101000011011110010010111001101000100011000011001011001001001001011111101000001100010100010111001111011010101001111010001010001111111100101010100111100001001001111101111101101110001001000110000

+ 1 - 0
2p-preprocessing/gamma1.txt

@@ -0,0 +1 @@
+1000010111101010011100110101010001101101000001101100110111100000000110000110001010110001111100110110001100001100101011011100000001000100111010111001000011100001001101011000100010110001000100001001100010110001001110111010000111000010111111110010000101111001

+ 48 - 0
2p-preprocessing/mpc.h

@@ -0,0 +1,48 @@
+
+
+void du_attalah_P2(std::vector<socket_t>& sockets0, std::vector<socket_t>& sockets1, int socket_no = 0)
+{
+int64_t X0, X1, Y0, Y1,  gamma0, gamma1;
+
+     arc4random_buf(&X0, sizeof(int64_t));
+     arc4random_buf(&Y0, sizeof(int64_t));
+     arc4random_buf(&X1, sizeof(int64_t));
+     arc4random_buf(&Y1, sizeof(int64_t));
+
+    gamma0 = X0 * Y1;
+    gamma1 = X1 * Y0;
+    
+ 
+
+    boost::asio::write(sockets0[socket_no], boost::asio::buffer(&X0, sizeof(X0)));
+    boost::asio::write(sockets1[socket_no], boost::asio::buffer(&X1, sizeof(X1)));
+    
+    boost::asio::write(sockets0[socket_no], boost::asio::buffer(&Y0, sizeof(Y0)));
+    boost::asio::write(sockets1[socket_no], boost::asio::buffer(&Y1, sizeof(Y1)));
+    
+    boost::asio::write(sockets0[socket_no], boost::asio::buffer(&gamma0, sizeof(gamma0)));
+    boost::asio::write(sockets1[socket_no], boost::asio::buffer(&gamma1, sizeof(gamma1)));
+}
+
+int64_t du_attalah_Pb(int64_t rb, int64_t pm, tcp::socket& s2, tcp::socket& sb)
+{
+    int64_t gamma;
+	int64_t X, Y;
+    int64_t rb_blinded, pm_blinded, pm_blinded_recv, rb_blinded_recv;
+	boost::asio::read(s2, boost::asio::buffer(&X, sizeof(X)));
+	boost::asio::read(s2, boost::asio::buffer(&Y, sizeof(Y)));
+	boost::asio::read(s2, boost::asio::buffer(&gamma, sizeof(gamma)));
+ 
+
+	rb_blinded = rb + X;
+	pm_blinded = pm + Y;
+	boost::asio::write(sb, boost::asio::buffer(&rb_blinded, sizeof(rb_blinded)));
+	boost::asio::read(sb, boost::asio::buffer(&rb_blinded_recv, sizeof(rb_blinded_recv)));
+	
+	boost::asio::write(sb, boost::asio::buffer(&pm_blinded, sizeof(pm_blinded)));
+	boost::asio::read(sb, boost::asio::buffer(&pm_blinded_recv, sizeof(pm_blinded_recv)));
+	
+	int64_t rb_prime = rb * (pm + (pm_blinded_recv)) - (Y * rb_blinded_recv) + gamma; 
+
+    return rb_prime;
+}

+ 397 - 0
2p-preprocessing/ot_blinds.cpp

@@ -0,0 +1,397 @@
+#include "ot_blinds.h"
+#include <cstdlib>
+#include <iostream>
+#include <ENCRYPTO_utils/connection.h> 
+#include <fstream>
+#include <x86intrin.h>  // SSE and AVX intrinsics
+const uint64_t n_OTS = 256;
+ 
+ot_ext_prot test_prots[] = {IKNP};
+snd_ot_flavor test_sflavor[] = {Snd_OT, Snd_C_OT, Snd_GC_OT, Snd_R_OT};
+rec_ot_flavor test_rflavor[] = {Rec_OT, Rec_R_OT};
+uint64_t test_numots[] = {n_OTS, 3215, 100000};
+uint64_t test_bitlen[] = {1, 3, 8, 191};
+uint32_t test_nthreads[] = {1, 4};
+field_type test_ftype[] = {P_FIELD, ECC_FIELD};
+bool test_usemecr[] = {false};
+
+BOOL Cleanup()
+{
+	delete sndthread;
+	delete rcvthread;
+
+	return true;
+}
+
+void InitSender(const std::string &address, const int port, CLock *glock)
+{
+	m_nPort = (uint16_t)port;
+	m_nAddr = &address;
+
+	//Server listen
+	m_Socket = Listen(address, port);
+	if (!m_Socket)
+	{
+		std::cerr << "Listen failed on " << address << ":" << port << "\n";
+		std::exit(1);
+	}
+
+	sndthread = new SndThread(m_Socket.get(), glock);
+	rcvthread = new RcvThread(m_Socket.get(), glock);
+
+	sndthread->Start();
+	rcvthread->Start();
+}
+
+void InitReceiver(const std::string &address, const int port, CLock *glock)
+{
+	m_nPort = (uint16_t)port;
+	m_nAddr = &address;
+
+	//Client connect
+	m_Socket = Connect(address, port);
+	if (!m_Socket)
+	{
+		std::cerr << "Connect failed on " << address << ":" << port << "\n";
+		std::exit(1);
+	}
+
+	sndthread = new SndThread(m_Socket.get(), glock);
+	rcvthread = new RcvThread(m_Socket.get(), glock);
+
+	sndthread->Start();
+	rcvthread->Start();
+}
+
+OTExtSnd *InitOTExtSnd(ot_ext_prot m_eProt, uint32_t nbaseots, uint32_t nchecks, bool enablemecr, field_type ftype, crypto *crypt)
+{
+	OTExtSnd *sender;
+	switch (m_eProt)
+	{
+	case ALSZ:
+		sender = new ALSZOTExtSnd(crypt, rcvthread, sndthread, nbaseots, nchecks);
+		break;
+	case IKNP:
+		sender = new IKNPOTExtSnd(crypt, rcvthread, sndthread);
+		break;
+	case NNOB:
+		sender = new NNOBOTExtSnd(crypt, rcvthread, sndthread);
+		break;
+	default:
+		sender = new ALSZOTExtSnd(crypt, rcvthread, sndthread, nbaseots, nchecks);
+		break;
+	}
+
+	if (enablemecr)
+		sender->EnableMinEntCorrRobustness();
+	sender->ComputeBaseOTs(ftype);
+	return sender;
+}
+
+OTExtRec *InitOTExtRec(ot_ext_prot m_eProt, uint32_t nbaseots, uint32_t nchecks, bool enablemecr, field_type ftype, crypto *crypt)
+{
+	OTExtRec *receiver;
+	switch (m_eProt)
+	{
+	case ALSZ:
+		receiver = new ALSZOTExtRec(crypt, rcvthread, sndthread, nbaseots, nchecks);
+		break;
+	case IKNP:
+		receiver = new IKNPOTExtRec(crypt, rcvthread, sndthread);
+		break;
+	case NNOB:
+		receiver = new NNOBOTExtRec(crypt, rcvthread, sndthread);
+		break;
+	default:
+		receiver = new ALSZOTExtRec(crypt, rcvthread, sndthread, nbaseots, nchecks);
+		break;
+	}
+
+	if (enablemecr)
+		receiver->EnableMinEntCorrRobustness();
+	receiver->ComputeBaseOTs(ftype);
+	return receiver;
+}
+
+// This is P0
+void run_test_sender(uint32_t numots, uint32_t bitlength, snd_ot_flavor stype, rec_ot_flavor rtype, uint32_t numthreads,
+					 crypto *crypt, OTExtSnd *sender, OTExtRec *receiver)
+{
+	CBitVector delta;
+	CBitVector X0;
+	uint32_t nsndvals = 2;
+	CBitVector **X = (CBitVector **)malloc(sizeof(CBitVector *) * nsndvals);
+	CBitVector **Y = (CBitVector **)malloc(sizeof(CBitVector *) * nsndvals);
+	CBitVector **XoplusY = (CBitVector **)malloc(sizeof(CBitVector *) * nsndvals);
+	//The masking function with which the values that are sent in the last communication step are processed
+	XORMasking *m_fMaskFct = new XORMasking(bitlength, delta);
+
+	//creates delta as an array with "numOTs" entries of "bitlength" bit-values and fills delta with random values
+	delta.Create(numots, bitlength, crypt);
+
+	//Create X1 and X2 as two arrays with "numOTs" entries of "bitlength" bit-values and resets them to 0
+	//X1.Create(numots, bitlength, crypt);
+	//X2.Create(numots, bitlength, crypt);
+
+	//X[0] --> T0 
+	//X[1] --> X0
+	//Y[0] --> Y0
+	printf("run_test_sender\n");
+	//(T, X0 \oplus T)
+	for (uint32_t i = 0; i < nsndvals; i++)
+	{
+		X[i] = new CBitVector();
+		// X[i]->Create(numots, bitlength, crypt);
+		X[i]->Create(numots, bitlength);
+        X[i]->FillRand(n_OTS, crypt);
+
+		Y[i] = new CBitVector();
+		// X[i]->Create(numots, bitlength, crypt);
+		Y[i]->Create(numots, bitlength);
+       
+	   // Y[i]->FillRand(n_OTS, crypt);
+		
+		 Y[i]->SetToOne();  // I added this line 
+        //X[i]->PrintBinary();  // I added this line 
+
+	}
+
+	 
+ 	X0.Create(numots, bitlength);
+	X0.Reset();
+	X0.XOR(X[1]);
+	//Y[0]->Copy(X[1]);
+	printf("X0:\n");
+	//X[1]->PrintBinary();  // I added this line 
+	X0.PrintHex();  // I added this line 
+	printf("Y0:\n");
+	Y[0]->PrintHex();  // I added this line
+	printf("T0: \n");
+	X[0]->PrintHex();
+	
+	X[1]->XOR(X[0]);
+
+	//X[1] --> X0 \oplus T0
+	//for (uint32_t i = 0; i < nsndvals; i++)
+	{
+	//   printf("T0:\n");
+    //   X[0]->PrintBinary();  // I added this line
+    //   printf("X0 ^ T0:\n");
+    //   X[1]->PrintBinary();  // I added this line 
+	}
+
+	sender->send(numots, bitlength, nsndvals, X, stype, rtype, numthreads, m_fMaskFct);
+	CBitVector response;
+
+
+	//Pre-generate the respose vector for the results
+	response.Create(numots, bitlength);
+	response.Reset();
+
+	//Y[0] is the choice vector.
+	receiver->receive(numots, bitlength, nsndvals, Y[0], &response, stype, rtype, numthreads, m_fMaskFct);
+	
+	
+	
+	response.XOR(X[0]);
+	
+	printf("\n\nLearnt Gamma0 = (X1 /cdot Y0) /oplus T------>>>>>> \n");
+	response.PrintHex();
+	 std::ofstream gammafile0, X0file, Y0file;
+	 gammafile0.open ("gamma0.txt", std::ios::out);
+	 X0file.open("X0.txt", std::ios::out);
+	 Y0file.open("Y0.txt", std::ios::out);
+	for(size_t j = 0; j < n_OTS; ++j)
+	{
+	//	std::cout << (int) response.GetBitNoMask(j);
+		gammafile0 << (int) response.GetBitNoMask(j);
+		X0file 	  << (int) X0.GetBitNoMask(j);
+		Y0file 	  << (int) Y[0]->GetBitNoMask(j);
+	}
+
+	for (uint32_t i = 0; i < nsndvals; i++)
+	{
+		delete (X[i]);
+	}
+	free(X);
+ 
+	delta.delCBitVector();
+	delete m_fMaskFct;
+}
+
+
+// This is P1
+void run_test_receiver(uint32_t numots, uint32_t bitlength, snd_ot_flavor stype, rec_ot_flavor rtype, uint32_t numthreads,
+					   crypto *crypt, OTExtSnd *sender, OTExtRec *receiver, int m_nPID)
+{
+	CBitVector X1, response;
+	uint32_t nsndvals = 2;
+
+	CBitVector **X = (CBitVector **)malloc(sizeof(CBitVector *) * nsndvals);
+	CBitVector **Y = (CBitVector **)malloc(sizeof(CBitVector *) * nsndvals);
+	
+
+	//X[0] --> T1 
+	//X[1] --> X1
+	//Y[0] --> Y1
+	for (uint32_t i = 0; i < nsndvals; i++)
+	{
+		X[i] = new CBitVector();
+		X[i]->Create(numots, bitlength);
+        X[i]->FillRand(n_OTS, crypt);
+
+		Y[i] = new CBitVector();
+		Y[i]->Create(numots, bitlength);
+        //Y[i]->FillRand(n_OTS, crypt);
+		 Y[i]->SetToOne(); 
+	}
+
+
+	X1.Create(numots, bitlength);
+	X1.Reset();
+	X1.XOR(X[1]);
+	printf("X1:\n");
+	//X[1]->PrintBinary();  // I added this line 
+	X1.PrintHex();  // I added this line 
+	printf("Y1:\n");
+	Y[0]->PrintHex();  // I added this line
+	printf("T1: \n");
+	X[0]->PrintHex();
+	
+	// X[1] -- > X1 \oplus T1
+	X[1]->XOR(X[0]);
+
+
+	//The masking function with which the values that are sent in the last communication step are processed
+	XORMasking *m_fMaskFct = new XORMasking(bitlength);
+
+ 
+
+ 
+
+	//Pre-generate the respose vector for the results
+	response.Create(numots, bitlength);
+	response.Reset();
+
+	/*
+	 * The inputs of the receiver in G_OT, C_OT and R_OT are the same. The only difference is the version
+	 * variable that has to match the version of the sender.
+	*/
+
+	//Learns: (X0 \cdot Y1) \oplus T0
+	//Y0 is the choice bits.
+	receiver->receive(numots, bitlength, nsndvals, Y[0], &response, stype, rtype, numthreads, m_fMaskFct);
+
+	sender->send(numots, bitlength, nsndvals, X, stype, rtype, numthreads, m_fMaskFct);
+
+	// printf("Learnt: (X0 /cdot Y1) /oplus T0------>>>>>> \n");
+
+	// response.PrintBinary();
+	response.XOR(X[0]);
+	printf("\n\nLearnt: Gamma1 =  (X0 /cdot Y1) /oplus T------>>>>>> \n");
+	response.PrintHex();
+	std::ofstream gammafile1, X1file, Y1file;
+	
+	
+	 gammafile1.open ("gamma1.txt", std::ios::out);
+	 X1file.open("X1.txt", std::ios::out);
+	 Y1file.open("Y1.txt", std::ios::out);
+	for(size_t j = 0; j < n_OTS; ++j)
+	{
+	//	std::cout << (int) response.GetBitNoMask(j);
+		gammafile1 << (int) response.GetBitNoMask(j);
+		X1file 	  << (int) X1.GetBitNoMask(j);
+		Y1file 	  << (int) Y[0]->GetBitNoMask(j);
+	}
+ 
+ 	gammafile1.close();
+	delete m_fMaskFct;
+//	choices.delCBitVector();
+	response.delCBitVector();
+}
+
+
+int main(int argc, char **argv)
+{
+	std::string addr0 = argv[1]; // "127.0.0.1";
+	std::string addr1 = argv[2]; // "127.0.0.1";
+	int port = 7766;
+
+	__m128i blinds;
+
+
+	// if (argc != 2)
+	// {
+	// 	std::cout << "Please call with 0 if acting as server or 1 if acting as client" << std::endl;
+	// 	return EXIT_FAILURE;
+	// }
+
+	//Determines whether the program is executed in the sender or receiver role
+	m_nPID = atoi(argv[3]);
+	std::cout << "Playing as role: " << m_nPID << std::endl;
+	assert(m_nPID >= 0 && m_nPID <= 1);
+
+	//The symmetric security parameter (80, 112, 128)
+	uint32_t m_nSecParam = 128;
+
+	crypto *crypt = new crypto(m_nSecParam, (uint8_t *)m_cConstSeed[m_nPID]);
+	CLock *glock = new CLock(); // pass this to sender and receiver constructors
+
+	uint32_t m_nBaseOTs = 190;
+	uint32_t m_nChecks = 380;
+
+	// NOTE: This vector controls the settings used by the oblivious transfer.
+	test_options selected_options; // = {IKNP, 128, 1, Snd_C_OT, Rec_OT, 1, ECC_FIELD, false};
+	selected_options.prot = IKNP;
+	selected_options.numots = n_OTS; // Number of OTs performed using the extended COT.
+	selected_options.bitlen = 1;
+	selected_options.sflavor = Snd_OT; //Snd_C_OT;
+	selected_options.rflavor = Rec_OT;
+	selected_options.nthreads = 1; // Number of threads
+	selected_options.ftype = P_FIELD; // Type of field to use for the base OT.
+	selected_options.usemecr = false;
+	// test_options selected_options = {IKNP, 128, 1, Snd_C_OT, Rec_OT, 1, P_FIELD, false}; // Alternative using P_FIELD
+	
+	if (m_nPID == SERVER_ID) //Play as OT sender
+	{
+		InitSender(addr0, port, glock);
+
+		OTExtSnd *sender = NULL;
+		
+		InitReceiver(addr1, port, glock);
+
+		OTExtRec *receiver = NULL;
+
+		sender = InitOTExtSnd(selected_options.prot, m_nBaseOTs, m_nChecks, selected_options.usemecr, selected_options.ftype, crypt);
+		receiver = InitOTExtRec(selected_options.prot, m_nBaseOTs, m_nChecks, selected_options.usemecr, selected_options.ftype, crypt);
+		std::cout << "--> : " << getProt(selected_options.prot) << " Sender " << selected_options.numots << " " << getSndFlavor(selected_options.sflavor) << " / " << getRecFlavor(selected_options.rflavor) << " on " << selected_options.bitlen << " bits with " << selected_options.nthreads << " threads, " << getFieldType(selected_options.ftype) << " and" << (selected_options.usemecr ? "" : " no") << " MECR" << std::endl;
+
+		run_test_sender(selected_options.numots, selected_options.bitlen, selected_options.sflavor, selected_options.rflavor, selected_options.nthreads, crypt, sender, receiver);
+
+		delete sender;
+	}
+	else //Play as OT receiver
+	{
+		InitReceiver(addr0, port, glock);
+
+		OTExtRec *receiver = NULL;
+
+			InitSender(addr1, port, glock);
+
+		OTExtSnd *sender = NULL;
+		receiver = InitOTExtRec(selected_options.prot, m_nBaseOTs, m_nChecks, selected_options.usemecr, selected_options.ftype, crypt);
+		sender = InitOTExtSnd(selected_options.prot, m_nBaseOTs, m_nChecks, selected_options.usemecr, selected_options.ftype, crypt);
+		std::cout << "--> : " << getProt(selected_options.prot) << " Receiver " << selected_options.numots << " " << getSndFlavor(selected_options.sflavor) << " / " << getRecFlavor(selected_options.rflavor) << " on " << selected_options.bitlen << " bits with " << selected_options.nthreads << " threads, " << getFieldType(selected_options.ftype) << " and" << (selected_options.usemecr ? "" : " no") << " MECR" << std::endl;
+
+		run_test_receiver(selected_options.numots, selected_options.bitlen, selected_options.sflavor, selected_options.rflavor, selected_options.nthreads, crypt, sender, receiver, m_nPID);
+
+		delete receiver;
+	}
+
+	Cleanup();
+	delete crypt;
+	delete glock;
+
+	return EXIT_SUCCESS;
+}
+

+ 73 - 0
2p-preprocessing/ot_blinds.h

@@ -0,0 +1,73 @@
+#ifndef _OTTEST_H_
+#define _OTTEST_H_
+
+#include <ENCRYPTO_utils/typedefs.h>
+#include <ENCRYPTO_utils/crypto/crypto.h>
+#include <ENCRYPTO_utils/socket.h>
+#include "ot/iknp-ot-ext-snd.h"
+#include "ot/iknp-ot-ext-rec.h"
+#include "ot/alsz-ot-ext-snd.h"
+#include "ot/alsz-ot-ext-rec.h"
+#include "ot/nnob-ot-ext-snd.h"
+#include "ot/nnob-ot-ext-rec.h"
+#include <ENCRYPTO_utils/cbitvector.h>
+#include "ot/xormasking.h"
+#include <ENCRYPTO_utils/rcvthread.h>
+#include <ENCRYPTO_utils/sndthread.h>
+#include <ENCRYPTO_utils/channel.h>
+#include <ENCRYPTO_utils/timer.h>
+
+#include <vector>
+#include <sys/time.h>
+
+#include <limits.h>
+#include <iomanip>
+#include <string>
+
+uint16_t m_nPort = 7894;
+const std::string* m_nAddr;
+
+static const char* m_cConstSeed[2] = {"437398417012387813714564100", "15657566154164561"};
+
+struct test_options {
+	ot_ext_prot	prot;
+	uint64_t numots;
+	uint64_t bitlen;
+	snd_ot_flavor sflavor;
+	rec_ot_flavor rflavor;
+	uint32_t nthreads;
+	field_type ftype;
+	bool usemecr;
+};
+
+test_options* tests;
+uint32_t m_nTests;
+uint32_t gen_tests;
+uint32_t m_nPID;
+
+void recursive_assign_test_params(uint32_t* max, uint32_t depth, test_options** tops, uint32_t max_depth);
+void assign_param(uint32_t ctr, uint32_t depth, test_options* tops);
+
+
+BOOL Init();
+BOOL Cleanup();
+BOOL Connect();
+BOOL Listen();
+
+void InitSender(const std::string& address, const int port, CLock *glock);
+void InitReceiver(const std::string& address, const int port, CLock *glock);
+
+OTExtSnd* InitOTExtSnd(ot_ext_prot m_eProt, uint32_t nbaseots, uint32_t nchecks, bool enablemecr, field_type ftype, crypto* crypt);
+OTExtRec* InitOTExtRec(ot_ext_prot m_eProt, uint32_t nbaseots, uint32_t nchecks, bool enablemecr, field_type ftype, crypto* crypt);
+
+void run_test_sender(uint32_t numots, uint32_t bitlength, snd_ot_flavor stype, rec_ot_flavor rtype, uint32_t numthreads, crypto* crypt, OTExtSnd* sender);
+void run_test_receiver(uint32_t numots, uint32_t bitlength, snd_ot_flavor stype, rec_ot_flavor rtype, uint32_t numthreads, crypto* crypt, OTExtRec* receiver);
+
+// Network Communication
+std::unique_ptr<CSocket> m_Socket;
+
+SndThread* sndthread;
+RcvThread* rcvthread;
+
+#endif
+

BIN
2p-preprocessing/party0_read_flags_b


BIN
2p-preprocessing/party1_read_flags_b


+ 671 - 0
2p-preprocessing/preprocessing.cpp

@@ -0,0 +1,671 @@
+#include <type_traits>  // std::is_same<>
+#include <limits>       // std::numeric_limits<>
+#include <climits>      // CHAR_BIT
+#include <cmath>        // std::log2, std::ceil, std::floor
+#include <stdexcept>    // std::runtime_error
+#include <array>        // std::array<>
+#include <iostream>     // std::istream and std::ostream
+#include <vector>       // std::vector<>
+#include <memory>       // std::shared_ptr<>
+#include <utility>      // std::move
+#include <algorithm>    // std::copy
+#include <cstring>      // std::memcpy
+
+#include <bsd/stdlib.h> // arc4random_buf
+#include <x86intrin.h>  // SSE and AVX intrinsics
+#include <boost/asio/thread_pool.hpp>
+#include "bitutils.h"
+#include "block.h"
+#include "prg.h"
+ 
+#include "prg_aes_impl.h"
+
+#include <iostream>
+ 
+#include <fcntl.h>
+#include <cstdlib>
+#include "block.h"
+#include <chrono>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fstream>
+#include <future>
+#include <boost/asio.hpp>
+
+using boost::asio::ip::tcp;
+
+ 
+
+#include <mutex>
+#include <boost/lexical_cast.hpp>
+ 
+
+ 
+
+using socket_t = boost::asio::ip::tcp::socket;
+ 
+typedef unsigned char byte_t;
+
+typedef __m128i node_t;
+block<__m128i> seed_for_blinds;
+constexpr size_t leaf_size = 1;
+typedef __m128i leaf_type;
+
+
+ 
+ 
+
+ typedef std::array<leaf_type, leaf_size> leaf_t;
+ 
+ 
+ size_t bits_per_leaf = std::is_same<leaf_t, bool>::value ? 1 : sizeof(leaf_t) * CHAR_BIT;
+ bool is_packed = (sizeof(leaf_t) < sizeof(node_t));
+ size_t leaves_per_node = is_packed ? sizeof(node_t) * CHAR_BIT / bits_per_leaf : 1;
+
+ size_t input_bits(const size_t nitems) { return std::ceil(std::log2(nitems)); }
+
+ leaf_t val;
+ 
+
+using namespace dpf;
+
+#include "mpc.h"
+ 
+
+void compute_CW(bool party, tcp::socket& sout,  __m128i L, __m128i R, uint8_t bit, __m128i & CW)
+{
+
+  	
+
+	
+	//struct cw_construction
+	//{
+	  __m128i rand_b, gamma_b;
+	  uint8_t bit_b;
+	//};
+
+
+	//cw_construction computecw;
+//	read(sin, boost::asio::buffer(&computecw, sizeof(computecw)));
+	 
+	//computecw.rand_b;
+	//__m128i gamma_b = computecw.gamma_b;
+
+	if(party)
+	{
+	 rand_b  = _mm_set_epi32(0x6fef9434, 0x6768121e, 0x20942286, 0x1b59f7a7);
+	 gamma_b = _mm_set_epi32(0x6a499109 , 0x803067dd , 0xd1e2281b , 0xe71b6262);
+	 bit_b   = 1;// computecw.bit_b;
+	}
+	else
+	{
+	  rand_b  = _mm_set_epi32(0xb29747df, 0xf7300f6d, 0x9476d971, 0xd5f75d98);
+	  gamma_b = _mm_set_epi32(0xb73142e2 , 0x10687aae , 0x06500d3ec , 0x29b5c85d);
+	  bit_b   = 1;// computecw.bit_b;
+	}
+	
+ 
+
+	// #ifdef DEBUG 
+	// 	__m128i rand_b2, gamma_b2;
+	// 	uint8_t bit_b2;
+	//  	read(sin, boost::asio::buffer(&rand_b2, sizeof(rand_b)));
+	//     read(sin, boost::asio::buffer(&gamma_b2, sizeof(gamma_b)));
+	//     read(sin, boost::asio::buffer(&bit_b2, sizeof(bit_b)));
+
+	//     assert(rand_b2[0] == rand_b[0]);
+	//     assert(rand_b2[1] == rand_b[1]);
+	// 	assert(gamma_b2[0] == gamma_b[0]);
+	//     assert(gamma_b2[1] == gamma_b[1]);
+	// 	assert(bit_b2 == bit_b);
+ 	// #endif
+
+	uint8_t blinded_bit, blinded_bit_read;
+	blinded_bit = bit ^ bit_b;
+
+	__m128i blinded_L = L ^ R ^ rand_b;
+	__m128i blinded_L_read; 
+
+
+	struct BlindsCW
+	{
+		__m128i blinded_message;
+		uint8_t blinded_bit;
+	};
+
+	BlindsCW blinds_sent, blinds_recv;
+
+	blinds_sent.blinded_bit = blinded_bit;
+	blinds_sent.blinded_message = blinded_L;
+
+ 
+ 
+ 	boost::asio::write(sout, boost::asio::buffer(&blinds_sent, sizeof(blinds_sent)));
+	boost::asio::read(sout, boost::asio::buffer(&blinds_recv, sizeof(blinds_recv)));
+	
+	blinded_bit_read = blinds_recv.blinded_bit;
+	blinded_L_read   =  blinds_recv.blinded_message;
+
+	__m128i out_ = R ^ gamma_b;//_mm_setzero_si128;
+
+	if(bit)
+	{
+	 out_ ^= (L ^ R ^ blinded_L_read);
+	}
+	if(blinded_bit_read)
+	{
+	 out_ ^= rand_b;
+	}
+
+	__m128i out_reconstruction; 
+	boost::asio::write(sout, boost::asio::buffer(&out_, sizeof(out_)));
+	boost::asio::read(sout, boost::asio::buffer(&out_reconstruction, sizeof(out_reconstruction)));
+	out_reconstruction = out_ ^ out_reconstruction;
+	
+	CW = out_reconstruction;
+	
+	// #ifdef DEBUG
+	// 	uint8_t bit_reconstruction; 
+	// 	boost::asio::write(sout, boost::asio::buffer(&bit, sizeof(bit)));
+	// 	boost::asio::read(sout, boost::asio::buffer(&bit_reconstruction, sizeof(bit_reconstruction)));
+	// 	bit_reconstruction = bit ^ bit_reconstruction;
+
+	// 	__m128i L_reconstruction; 
+	// 	boost::asio::write(sout, boost::asio::buffer(&L, sizeof(L)));
+	// 	boost::asio::read(sout, boost::asio::buffer(&L_reconstruction, sizeof(L_reconstruction)));
+	// 	L_reconstruction = L ^ L_reconstruction;
+
+	// 	__m128i R_reconstruction; 
+	// 	boost::asio::write(sout, boost::asio::buffer(&R, sizeof(R)));
+	// 	boost::asio::read(sout, boost::asio::buffer(&R_reconstruction, sizeof(R_reconstruction)));
+	// 	R_reconstruction = R ^ R_reconstruction;
+
+	//  	__m128i CW_debug;
+
+	// 	if(bit_reconstruction != 0)
+	// 	{
+	// 	  CW_debug = L_reconstruction;
+	// 	}
+	// 	else
+	// 	{
+	// 	  CW_debug = R_reconstruction;
+	// 	}
+
+	// 	assert(CW_debug[0] == CW[0]);
+	// 	assert(CW_debug[1] == CW[1]);
+	// #endif
+	
+}
+
+ 
+
+__m128i bit_mask_avx2_msb(unsigned int n)
+{
+    __m128i ones       = _mm_set1_epi32(-1);
+    __m128i cnst32_128 = _mm_set_epi32(32,64,96,128);
+
+    __m128i shift      = _mm_set1_epi32(n);
+            shift      = _mm_subs_epu16(cnst32_128,shift);
+                  return _mm_sllv_epi32(ones,shift);
+}
+
+
+__m128i bit_mask_avx2_lsb(unsigned int n)
+{
+    __m128i ones       = _mm_set1_epi32(-1);
+    __m128i cnst32_128 = _mm_set_epi32(128,96,64,32);
+
+    __m128i shift      = _mm_set1_epi32(n);
+            shift      = _mm_subs_epu16(cnst32_128,shift);
+                  return _mm_srlv_epi32(ones,shift);
+}
+
+template<typename node_t, typename prgkey_t>
+static inline void traverse(const prgkey_t & prgkey, const node_t & seed,	node_t s[2])
+{	
+	dpf::PRG(prgkey, clear_lsb(seed, 0b11), s, 2);
+} // dpf::expand
+
+ 
+
+
+inline void evalfull_mpc(const size_t& nodes_per_leaf, const size_t& depth, const size_t& nbits, const size_t& nodes_in_interval, 
+							 const AES_KEY& prgkey,  uint8_t target_share[64], std::vector<socket_t>& socketsPb, 
+							 const size_t from, const size_t to, __m128i * output, int8_t * _t, __m128i& final_correction_word, bool party, size_t socket_no = 0)
+{
+
+	
+	__m128i root;
+	
+	arc4random_buf(&root, sizeof(root));
+    
+    root =	set_lsb(root, party);
+
+	const size_t from_node = std::floor(static_cast<double>(from) / nodes_per_leaf);
+
+	__m128i * s[2] = {
+	    reinterpret_cast<__m128i *>(output) + nodes_in_interval * (nodes_per_leaf - 1),
+	    s[0] + nodes_in_interval / 2
+	};
+	
+	int8_t * t[2] = { _t, _t + nodes_in_interval / 2};
+
+	int curlayer = depth % 2;
+
+	s[curlayer][0] = root;
+	t[curlayer][0] = get_lsb(root, 0b01);
+	
+	__m128i * CW = (__m128i *) std::aligned_alloc(sizeof(__m256i), depth * sizeof(__m128i));
+
+	for (size_t layer = 0; layer < depth; ++layer)
+	{
+		#ifdef VERBOSE	
+			printf("layer = %zu\n", layer);
+		#endif
+		curlayer = 1-curlayer;
+
+		size_t i=0, j=0;
+		auto nextbit = (from_node >> (nbits-layer-1)) & 1;
+		size_t nodes_in_prev_layer = std::ceil(static_cast<double>(nodes_in_interval) / (1ULL << (depth-layer)));
+		size_t nodes_in_cur_layer = std::ceil(static_cast<double>(nodes_in_interval) / (1ULL << (depth-layer-1)));
+
+	
+		__m128i L =  _mm_setzero_si128();
+		__m128i R =  _mm_setzero_si128();
+		
+		for (i = nextbit, j = nextbit; j < nodes_in_prev_layer-1; ++j, i+=2)
+		{
+			traverse(prgkey, s[1-curlayer][j], &s[curlayer][i]);
+			L ^= s[curlayer][i];
+			R ^= s[curlayer][i+1];
+		}
+		
+		if (nodes_in_prev_layer > j)
+		{
+			if (i < nodes_in_cur_layer - 1) 
+			{
+				traverse(prgkey, s[1-curlayer][j], &s[curlayer][i]);
+				L ^= s[curlayer][i];
+				R ^= s[curlayer][i+1];
+			}
+		}
+
+		compute_CW(party, socketsPb[socket_no],  L,  R, target_share[layer], CW[layer]);
+
+		uint8_t advice_L = get_lsb(L) ^ target_share[layer];
+	 	uint8_t advice_R = get_lsb(R) ^ target_share[layer];
+
+	 	uint8_t cwt_L, cwt_R;
+	 
+	 	uint8_t advice[2];
+	 	uint8_t cwts[2];	
+	 	advice[0] = advice_L;
+	 	advice[1] = advice_R;
+	 	
+	 	boost::asio::write(socketsPb[socket_no+1], boost::asio::buffer(&advice, sizeof(advice)));
+	 	boost::asio::read(socketsPb[socket_no+1], boost::asio::buffer(&cwts, sizeof(cwts)));
+		
+		cwt_L = cwts[0];
+		cwt_R = cwts[1];
+
+		cwt_L = cwt_L ^ advice_L ^ 1;
+	 	cwt_R = cwt_R ^ advice_R;	 	
+ 
+		for(size_t j = 0; j < nodes_in_prev_layer; ++j)
+		{	
+			t[curlayer][2*j] 	 = get_lsb(s[curlayer][2*j]) ^ (cwt_L & t[1-curlayer][j]);
+			s[curlayer][2*j] 	 = clear_lsb(xor_if(s[curlayer][2*j], CW[layer], !t[1-curlayer][j]), 0b11);
+			t[curlayer][(2*j)+1] = get_lsb(s[curlayer][(2*j)+1]) ^ (cwt_R & t[1-curlayer][j]);
+			s[curlayer][(2*j)+1] = clear_lsb(xor_if(s[curlayer][(2*j)+1], CW[layer], !t[1-curlayer][j]), 0b11);
+		}
+	}
+
+		
+	__m128i Gamma  =  _mm_setzero_si128();
+	 
+	for (size_t i = 0; i < to + 1; ++i)
+	{
+	  Gamma[0] += output[i][0];
+	  Gamma[1] += output[i][1];
+	}
+		
+	if(party) 
+	{
+	  Gamma[0] = -Gamma[0];
+	  Gamma[1] = -Gamma[1];
+	}
+	
+	boost::asio::write(socketsPb[socket_no + 3], boost::asio::buffer(&Gamma, sizeof(Gamma)));
+ 	boost::asio::read(socketsPb[socket_no + 3], boost::asio::buffer(&final_correction_word, sizeof(final_correction_word)));
+
+ 	final_correction_word = Gamma; // final_correction_word + Gamma;
+
+} // dpf::__evalinterval
+
+
+void convert_shares(__m128i ** output, int8_t ** flags, size_t n_threads, size_t db_nitems, __m128i * final_correction_word, tcp::socket& sb,  bool party)
+{
+	
+ 
+	for(size_t j = 0; j < db_nitems; ++j)
+	{		
+		for(size_t k = 0; k < n_threads; ++k)
+		{
+			if(party)
+			{
+				output[k][j] = -output[k][j];
+				flags[k][j]  =  -flags[k][j]; 
+			}
+		}
+
+		//#ifdef DEBUG
+			int8_t out = flags[0][j];
+			int8_t out_rec; 
+
+			boost::asio::write(sb, boost::asio::buffer(&out, sizeof(out)));
+			boost::asio::read(sb, boost::asio::buffer(&out_rec, sizeof(out_rec)));
+			out_rec = out_rec + out;
+
+			if(out_rec != 0) std::cout << j << "(flags) --> " << (int) out_rec << std::endl  << std::endl;
+
+			__m128i out2 = output[0][j];
+			__m128i out_rec2;	
+
+			boost::asio::write(sb, boost::asio::buffer(&out2, sizeof(out2)));
+			boost::asio::read(sb, boost::asio::buffer(&out_rec2, sizeof(out_rec2)));
+			out_rec2 = out_rec2 + out2;
+			if(out_rec2[0] != 0)std::cout << j << "--> " << out_rec2[0] << std::endl;
+		//#endif		
+	}
+
+for(size_t i = 0; i < n_threads; ++i)
+{
+
+	int64_t pm = 0;
+	int64_t rb;
+
+	arc4random_buf(&rb, sizeof(rb));
+	for(size_t j = 0; j < db_nitems; ++j)
+	{
+		if(party)
+		{
+		  if(flags[i][j] != 0)	pm -= 1;
+		}
+		if(!party)
+		{
+		 if(flags[i][j] != 0)	pm += 1;//flags[0][j];
+		}
+	}
+
+//  int64_t rp_prime;
+// 	rb_prime = du_attalah_Pb(rb, pm, s2, sb);
+
+// 	int64_t FCWshare = du_attalah_Pb(final_correction_word[i][1] + rb_prime, pm, s2, sb);
+
+// 	int64_t FCWshare_reconstruction;
+//  	boost::asio::write(sb, boost::asio::buffer(&FCWshare, sizeof(FCWshare)));
+// 	boost::asio::read(sb, boost::asio::buffer(&FCWshare_reconstruction, sizeof(FCWshare_reconstruction)));
+// 	FCWshare_reconstruction = FCWshare_reconstruction + FCWshare;
+
+// 	int64_t PM = pm + rb;
+// 	int64_t PM_recv;
+
+// 	boost::asio::write(sb, boost::asio::buffer(&PM, sizeof(PM)));
+// 	boost::asio::read(sb, boost::asio::buffer(&PM_recv, sizeof(PM_recv)));
+    
+//     int64_t * flags_  = (int64_t *)std::aligned_alloc(sizeof(node_t), db_nitems * sizeof(int64_t));
+// 	for(size_t j = 0; j < db_nitems; ++j)
+// 	{
+// 		flags_[j] = (flags[i][j] * pm) + (flags[i][j] * PM_recv) + (flags[i][j] * rb); 
+	
+// 		#ifdef DEBUG
+// 			// int64_t flags_rec;
+// 			// boost::asio::write(sb, boost::asio::buffer(&flags_[j], sizeof(flags_[j])));
+// 			// boost::asio::read(sb, boost::asio::buffer(&flags_rec, sizeof(flags_rec)));
+// 			// flags_rec = flags_rec + flags_[j];
+// 			// if(flags_rec != 0) std::cout << "intermediate value = " << flags_rec << std::endl;
+// 		#endif
+// 	}
+ 
+ 
+// 	for(size_t j = 0; j < db_nitems; ++j)
+// 	{
+// 		flags_[j] += output[i][j][1]; 
+
+// 		if(!party)
+// 		{	
+// 			if(flags[i][j] != 0) flags_[j] -= FCWshare_reconstruction;//(rb_reconstruction) + rbpm_fcw;
+// 		}
+// 		if(party)
+// 		{ 
+// 			if(flags[i][j] != 0) flags_[j] += FCWshare_reconstruction;// (rb_reconstruction) + rbpm_fcw;
+// 		}
+
+// 		#ifdef DEBUG
+// 		int64_t flags_rec;
+// 		boost::asio::write(sb, boost::asio::buffer(&flags_[j], sizeof(flags_[j])));
+// 		boost::asio::read(sb, boost::asio::buffer(&flags_rec, sizeof(flags_rec)));
+// 		flags_rec = flags_rec + flags_[j];
+
+// 		if(flags_rec != 0)
+// 		{
+// 			printf("flag reconstruction = %ld\n", flags_rec);
+// 		}
+// 		#endif
+// 	}
+	
+	//std::cout << std::endl << std::endl << " ------------------------------------------------------------------------------------------ " << std::endl << std::endl;
+}
+
+ }
+ 
+ void accept_conncections_from_Pb(boost::asio::io_context&io_context, std::vector<socket_t>& socketsPb, int port, size_t j)
+{
+ 	 tcp::acceptor acceptor_a(io_context, tcp::endpoint(tcp::v4(), port));
+	 tcp::socket sb_a(acceptor_a.accept());
+	 socketsPb[j] = std::move(sb_a); 
+}
+
+
+int main(int argc, char * argv[])
+{ 	
+	
+ 
+	
+
+	boost::asio::io_context io_context;
+    tcp::resolver resolver(io_context);
+ 	std::string addr = "127.0.0.1";
+	const std::string host1 = (argc < 2) ? "127.0.0.1" : argv[1];
+	const std::string host2 = (argc < 3) ? "127.0.0.1" : argv[2];
+	
+	const size_t n_threads = atoi(argv[3]);
+	const size_t number_of_sockets = 5 * n_threads;
+	
+
+ 
+	std::vector<socket_t> socketsPb;
+ 	for(size_t j = 0; j < number_of_sockets + 1; ++j)
+ 	{
+ 		tcp::socket emptysocket(io_context);
+ 		socketsPb.emplace_back(std::move(emptysocket));
+ 	}
+	socketsPb.reserve(number_of_sockets + 1);
+
+	//std::vector<socket_t> socketsP2;
+
+	std::vector<int> ports;
+	for(size_t j = 0; j < number_of_sockets; ++j) 
+	{
+		int port = 6000;
+		ports.push_back(port + j);
+	}
+	
+	std::vector<int> ports2_0;
+	for(size_t j = 0; j < number_of_sockets; ++j) 
+	{
+		int port = 20000;
+		ports2_0.push_back(port + j);
+	}
+
+	std::vector<int> ports2_1;
+	for(size_t j = 0; j < number_of_sockets; ++j) 
+	{
+		int port = 40000;
+		ports2_1.push_back(port + j);
+	}
+ 
+  bool party;
+   
+ 
+
+
+  #if (PARTY == 0)    
+  	 
+  	party = false;
+    // for(size_t j = 0; j < number_of_sockets; ++j)
+    // {
+    //   tcp::socket sb_a(io_context);
+    //   boost::asio::connect(sb_a, resolver.resolve({host2, std::to_string(ports2_0[j])}));
+    //   socketsP2.emplace_back(std::move(sb_a)); 
+    // }
+ 
+    for(size_t j = 0; j < number_of_sockets; ++j)
+    {
+  	   tcp::socket sb_a(io_context);
+       boost::asio::connect(sb_a, resolver.resolve({host1, std::to_string(ports[j])}));
+ 	   socketsPb[j] = std::move(sb_a); 
+    }
+
+ #else	
+
+	party = true;	
+ 
+	for(size_t j = 0; j < number_of_sockets; ++j)
+    {
+    //   tcp::socket sb_a(io_context);
+    //   boost::asio::connect(sb_a, resolver.resolve({host2, std::to_string(ports2_1[j])}));
+    //   socketsP2.emplace_back(std::move(sb_a)); 
+    }
+  
+   boost::asio::thread_pool pool2(number_of_sockets); 
+  
+   for(size_t j = 0; j < number_of_sockets; ++j)
+   {
+	boost::asio::post(pool2, std::bind(accept_conncections_from_Pb,  std::ref(io_context), std::ref(socketsPb), ports[j],  j));
+   }
+  
+   pool2.join();
+#endif
+ 
+
+const size_t db_nitems = 1ULL << atoi(argv[4]);
+const size_t n_writes = atoi(argv[5]);
+const size_t n_reads  = atoi(argv[6]);
+
+std::cout << "n_reads = " << n_reads << std::endl;
+std::cout << "n_writes = " << n_writes << std::endl;
+ 
+
+__m128i * final_correction_word = (__m128i *) std::aligned_alloc(sizeof(__m256i), n_threads * sizeof(__m128i));
+ 
+uint8_t target_share[64];
+ 
+ int** target_share_written = new int*[n_writes];
+ for(size_t i = 0; i < n_writes; i++)
+ {
+    target_share_written[i] = new int[64];
+ }
+
+int** target_share_read = new int*[n_reads];
+for(size_t i = 0; i < n_reads; i++)
+ {
+    target_share_read[i] = new int[64];
+ }
+
+
+for(size_t j = 0; j < 64; ++j)
+{
+ 	target_share[j] = rand();
+	target_share[j] = target_share[j] % 2;	
+
+	for(size_t i = 0; i < n_writes; ++i)
+	{
+		srand(2);
+		target_share_written[i][j] = rand();
+		target_share_written[i][j] = target_share_written[i][j] % 2;	
+	}
+
+	for(size_t i = 0; i < n_reads; ++i)
+	{
+		srand(3);
+		target_share_read[i][j] = rand();
+		target_share_read[i][j] = target_share_read[i][j] % 2;	
+	}
+}
+
+AES_KEY aeskey;
+		
+
+__m128i ** output = (__m128i ** ) malloc(sizeof(__m128i *) * n_threads);
+int8_t ** flags  = (int8_t ** ) malloc(sizeof(uint8_t *) * n_threads);
+	 
+for(size_t j = 0; j < n_threads; ++j)
+{
+ output[j] = (__m128i *)std::aligned_alloc(sizeof(node_t), db_nitems * sizeof(__m128i));
+ flags[j]  = (int8_t *)std::aligned_alloc(sizeof(node_t), db_nitems * sizeof(uint8_t));
+}
+	
+const size_t bits_per_leaf = std::is_same<leaf_t, bool>::value ? 1 : sizeof(leaf_t) * CHAR_BIT;
+const bool is_packed = (sizeof(leaf_t) < sizeof(node_t));
+const size_t nodes_per_leaf = is_packed ? 1 : std::ceil(static_cast<double>(bits_per_leaf) / (sizeof(node_t) * CHAR_BIT));
+const size_t depth = std::ceil(std::log2(db_nitems));
+const size_t nbits = std::ceil(std::log2(db_nitems));
+const size_t nodes_in_interval = db_nitems-1;
+
+boost::asio::thread_pool pool(n_threads);
+
+printf("n_threads = %zu\n\n", n_threads);
+
+auto start = std::chrono::steady_clock::now();
+
+for(size_t j = 0; j < n_threads; ++j)
+{
+ 	boost::asio::post(pool,  std::bind(evalfull_mpc, std::ref(nodes_per_leaf), std::ref(depth), std::ref(nbits), std::ref(nodes_in_interval), 
+						  std::ref(aeskey),  target_share,  std::ref(socketsPb), 0, db_nitems-1, output[j], 
+		 				  flags[j], std::ref(final_correction_word[j]), party, 5 * j));	 	  
+}
+
+pool.join();  
+auto end = std::chrono::steady_clock::now();
+std::chrono::duration<double> elapsed_seconds = end-start;
+std::cout << "time to generate and evaluate " << n_threads << " dpfs of size 2^" << atoi(argv[4]) << " is: " << elapsed_seconds.count() << "s\n";
+ 
+convert_shares(output, flags, n_threads, db_nitems ,final_correction_word, socketsPb[0], party);
+
+ if(!party)
+ {
+   char const * p0_filename0;
+   p0_filename0 = "party0_read_flags_b";
+   int w0 = open( p0_filename0, O_WRONLY | O_CREAT, S_IWRITE | S_IREAD);
+   int written = write(w0, flags[0], db_nitems * sizeof(flags[0][0]));
+      if(written<0) {
+             perror("Write error");
+       }
+      close(w0);
+  }
+  else
+  {
+	char const * p0_filename0;
+    p0_filename0 = "party1_read_flags_b";
+    int w0 = open( p0_filename0, O_WRONLY | O_CREAT, S_IWRITE | S_IREAD);
+    int written = write(w0, flags[0], db_nitems * sizeof(flags[0][0]));
+      if(written<0) {
+             perror("Write error");
+       }
+      close(w0);	
+  }
+
+	return 0;
+}

+ 20 - 0
2p-preprocessing/prg.h

@@ -0,0 +1,20 @@
+/* Copyright (C) 2019  Anonymous
+ *
+ * This is a pre-release version of the DPF++ library distributed anonymously
+ * for peer review. A public release of the software will be published under the
+ * LPGL v2.1 license in the near future. Please do not redistribute this version
+ * of the software.
+ */
+
+#ifndef DPFPP_PRG_H__
+#define DPFPP_PRG_H__
+ 
+namespace dpf
+{
+
+template<typename node_t, typename lowmc>
+inline void PRG(const lowmc & prgkey, const node_t & seed, void * outbuf, const uint32_t len, const uint32_t from = 0);
+ 
+
+} // namespace dpf
+#endif // DPFPP_PRG_H

+ 73 - 0
2p-preprocessing/prg_aes_impl.h

@@ -0,0 +1,73 @@
+/* Copyright (C) 2019  Anonymous
+ *
+ * This is a pre-release version of the DPF++ library distributed anonymously
+ * for peer review. A public release of the software will be published under the
+ * LPGL v2.1 license in the near future. Please do not redistribute this version
+ * of the software.
+ */
+
+#ifndef DPFPP_PRG_AES_IMPL_H__
+#define DPFPP_PRG_AES_IMPL_H__
+
+#include "prg.h"
+#include "aes.h"
+
+namespace dpf
+{
+
+template<>
+inline void PRG(const AES_KEY & prgkey, const __m128i & seed, void * outbuf, const uint32_t len, const uint32_t from)
+{
+ 
+	__m128i * outbuf128 = reinterpret_cast<__m128i *>(outbuf);
+	for (size_t i = 0; i < len; ++i)
+	{
+		outbuf128[i] = _mm_xor_si128(seed, _mm_set_epi64x(0, from+i));
+	}
+	AES_ecb_encrypt_blks(outbuf128, static_cast<unsigned int>(len), &prgkey);
+	for (size_t i = 0; i < len; ++i) 
+	{
+		outbuf128[i] = _mm_xor_si128(outbuf128[i], _mm_set_epi64x(0, from+i));
+		outbuf128[i] = _mm_xor_si128(outbuf128[i], seed);
+	}
+} // PRG<AES_KEY>
+inline void PRG_aes(const AES_KEY & prgkey, const __m128i & seed, void * outbuf, const uint32_t len, const uint32_t from = 0)
+{
+	__m128i * outbuf128 = reinterpret_cast<__m128i *>(outbuf);
+	for (size_t i = 0; i < len; ++i)
+	{
+		outbuf128[i] = _mm_xor_si128(seed, _mm_set_epi64x(0, from+i));
+	}
+	AES_ecb_encrypt_blks(outbuf128, static_cast<unsigned int>(len), &prgkey);
+	for (size_t i = 0; i < len; ++i) 
+	{
+		outbuf128[i] = _mm_xor_si128(outbuf128[i], _mm_set_epi64x(0, from+i));
+		outbuf128[i] = _mm_xor_si128(outbuf128[i], seed);
+	}
+} // PRG<AES_KEY>
+
+
+inline void PRG_aes(const AES_KEY & prgkey, const __m256i & seed, void * outbuf, const uint32_t len, const uint32_t from = 0)
+{
+	 __m256i * outbuf256 = reinterpret_cast<__m256i *>(outbuf);
+	 for (size_t i = 0; i < len; ++i)
+	 {
+	 	outbuf256[i] = _mm256_xor_si256(seed, _mm256_set_epi64x(0, 0, 0, from+i));
+	 }
+	
+	// AES_ecb_encrypt_blks(reinterpret_cast<__m128i *>(outbuf256), static_cast<unsigned int>(len), &prgkey);
+	
+	 for (size_t i = 0; i < len; ++i) 
+	 {
+		outbuf256[i] = _mm256_xor_si256(outbuf256[i], _mm256_set_epi64x(0, 0, 0, from+i));
+		outbuf256[i] = _mm256_xor_si256(outbuf256[i], seed);
+	 }
+} // PRG<AES_KEY>
+inline std::ostream & operator<<(std::ostream & os, const AES_KEY & prgkey)
+{
+	return os.write(reinterpret_cast<const char *>(&prgkey.rd_key[0]), sizeof(__m128i));
+} // operator<<
+
+} // namespace dpf
+
+#endif // DPFPP_PRG_AES_IMPL_H

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