├── test ├── ands.txt ├── simple_circuit.cpp ├── aes.cpp ├── sha1.cpp ├── sha256.cpp ├── triple.cpp ├── aes_mult_inputs.cpp ├── generate_circuit.cpp ├── 2pc_scal.cpp ├── CMakeLists.txt ├── abit.cpp ├── 2pc.cpp ├── amortized_2pc.cpp ├── amortized_2pc2.cpp └── single_execution.h ├── emp-ag2pc ├── emp-ag2pc.h ├── config.h ├── leaky_deltaot.h ├── feq.h ├── helper.h ├── fpre.h ├── 2pc.h └── amortized_2pc.h ├── cmake └── emp-ag2pc-config.cmake ├── CMakeLists.txt ├── .gitignore ├── run ├── .github └── workflows │ ├── arm.yml │ ├── x86.yml │ └── codeql.yml ├── lgtm.yml ├── LICENSE └── README.md /test/ands.txt: -------------------------------------------------------------------------------- 1 | 6 14 2 | 4 4 6 3 | 4 | 2 1 0 4 8 AND 5 | 2 1 1 5 9 AND 6 | 2 1 2 6 10 AND 7 | 2 1 3 7 11 AND 8 | 1 1 8 12 INV 9 | 2 1 9 12 13 AND 10 | -------------------------------------------------------------------------------- /emp-ag2pc/emp-ag2pc.h: -------------------------------------------------------------------------------- 1 | #include "emp-ag2pc/2pc.h" 2 | #include "emp-ag2pc/helper.h" 3 | #include "emp-ag2pc/amortized_2pc.h" 4 | #include "emp-ag2pc/feq.h" 5 | #include "emp-ag2pc/config.h" 6 | #include "emp-ag2pc/fpre.h" -------------------------------------------------------------------------------- /emp-ag2pc/config.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AG2PC_CONFIG_H__ 2 | #define EMP_AG2PC_CONFIG_H__ 3 | namespace emp { 4 | const static int fpre_threads = 1; 5 | const static char * IP = "127.0.0.1"; 6 | //const static char * IP = "172.31.10.128"; 7 | } 8 | #endif// __C2PC_CONFIG 9 | -------------------------------------------------------------------------------- /cmake/emp-ag2pc-config.cmake: -------------------------------------------------------------------------------- 1 | find_package(emp-ot) 2 | 3 | find_path(EMP-AG2PC_INCLUDE_DIR emp-ag2pc/emp-ag2pc.h) 4 | 5 | include(FindPackageHandleStandardArgs) 6 | 7 | find_package_handle_standard_args(emp-ag2pc DEFAULT_MSG EMP-AG2PC_INCLUDE_DIR) 8 | 9 | if(EMP-AG2PC_FOUND) 10 | set(EMP-AG2PC_INCLUDE_DIRS ${EMP-AG2PC_INCLUDE_DIR} ${EMP-OT_INCLUDE_DIRS}) 11 | set(EMP-AG2PC_LIBRARIES ${EMP-OT_LIBRARIES}) 12 | endif() 13 | -------------------------------------------------------------------------------- /test/simple_circuit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test/single_execution.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | int main(int argc, char** argv) { 7 | int party, port; 8 | parse_party_and_port(argv, &party, &port); 9 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 10 | //io->set_nodelay(); 11 | test(party, io, "test/ands.txt"); 12 | delete io; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/aes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test/single_execution.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | int main(int argc, char** argv) { 7 | int party, port; 8 | parse_party_and_port(argv, &party, &port); 9 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 10 | // io->set_nodelay(); 11 | test(party, io, circuit_file_location+"AES-non-expanded.txt"); 12 | delete io; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/sha1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test/single_execution.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | int main(int argc, char** argv) { 7 | int party, port; 8 | parse_party_and_port(argv, &party, &port); 9 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 10 | // io->set_nodelay(); 11 | test(party, io, circuit_file_location+"sha-1.txt", string("92b404e556588ced6c1acd4ebf053f6809f73a93")); 12 | delete io; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test/single_execution.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | int main(int argc, char** argv) { 7 | int party, port; 8 | parse_party_and_port(argv, &party, &port); 9 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 10 | // io->set_nodelay(); 11 | test(party, io, circuit_file_location+"sha-256.txt", "da5698be17b9b46962335799779fbeca8ce5d491c0d26243bafef9ea1837a9d8"); 12 | delete io; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0...4.1.2) 2 | project (emp-ag2pc) 3 | set(NAME "emp-ag2pc") 4 | 5 | find_path(CMAKE_FOLDER NAMES cmake/emp-tool-config.cmake) 6 | include(${CMAKE_FOLDER}/cmake/emp-base.cmake) 7 | 8 | FIND_PACKAGE(emp-ot REQUIRED) 9 | INCLUDE_DIRECTORIES(${EMP-OT_INCLUDE_DIRS}) 10 | 11 | # Installation 12 | install(FILES cmake/emp-ag2pc-config.cmake DESTINATION cmake/) 13 | install(DIRECTORY emp-ag2pc DESTINATION include) 14 | 15 | ENABLE_TESTING() 16 | ADD_SUBDIRECTORY(test) 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *Testing 2 | *CTestTestfile.cmake 3 | CMakeCache.txt 4 | CMakeFiles/ 5 | Makefile 6 | bin/ 7 | cmake_install.cmake 8 | install_manifest.txt 9 | 10 | # Compiled Object files 11 | *.slo 12 | *.lo 13 | *.o 14 | *.obj 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Compiled Dynamic libraries 21 | *.so 22 | *.dylib 23 | *.dll 24 | 25 | # Fortran module files 26 | *.mod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | perf.data* 40 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ "$1" == "-p1" ] 3 | then 4 | shift 5 | perf record $1 1 12345 & (sleep 0.1; $1 2 12345) 6 | elif [ "$1" == "-p2" ] 7 | then 8 | shift 9 | (sleep 0.1; $1 1 12345) & (perf record $1 2 12345) 10 | 11 | elif [ "$1" == "-m1" ] 12 | then 13 | shift 14 | valgrind --leak-check=full $1 1 12345 & $1 2 12345 15 | elif [ "$1" == "-m2" ] 16 | then 17 | shift 18 | $1 1 12345 & valgrind --leak-check=full $1 2 12345 19 | elif [ "$1" == "-t1" ] 20 | then 21 | shift 22 | time $1 1 12345 & $1 2 12345 23 | elif [ "$1" == "-t2" ] 24 | then 25 | shift 26 | $1 1 12345 & time $1 2 12345 27 | 28 | else 29 | (sleep 0.05; $1 1 12345) & $1 2 12345 30 | fi 31 | -------------------------------------------------------------------------------- /test/triple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emp-ag2pc/fpre.h" 3 | #include 4 | using namespace std; 5 | using namespace emp; 6 | 7 | int N = 1<<20; 8 | int main(int argc, char** argv) { 9 | int port, party; 10 | parse_party_and_port(argv, &party, &port); 11 | 12 | NetIO *io; 13 | io = new NetIO(party==ALICE ? nullptr:IP, port); 14 | Fpre * fpre = new Fpre(io, party, N); 15 | auto tt1 = clock_start(); 16 | fpre->refill(); 17 | //fpre->refill(); 18 | cout << time_from(tt1)/(N)*1000<bandwidth()<check_correctness(fpre->MAC_res, fpre->KEY_res, fpre->batch_size); 22 | delete fpre; 23 | delete io; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/arm.yml: -------------------------------------------------------------------------------- 1 | name: arm 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build_arm: 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest] 9 | build_type: [Debug, Release] 10 | runs-on: [self-hosted] 11 | timeout-minutes: 30 12 | env: 13 | BUILD_TYPE: ${{matrix.build_type}} 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: install dependency 17 | run: | 18 | wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py 19 | python3 install.py --install --tool --ot 20 | - name: Create Build Environment 21 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE && make 22 | - name: Test 23 | shell: bash 24 | run: make test 25 | -------------------------------------------------------------------------------- /test/aes_mult_inputs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test/single_execution.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | 7 | int main(int argc, char** argv) { 8 | int party, port; 9 | parse_party_and_port(argv, &party, &port); 10 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 11 | // io->set_nodelay(); 12 | // 13 | // NIST test vector 14 | string input_message_key = "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F"; 15 | string expected_output = "69C4E0D86A7B0430D8CDB78070B4C55A"; 16 | 17 | test(party, io, circuit_file_location+"AES-non-expanded.txt", expected_output, input_message_key); 18 | //cout << "expected output: " << endl << hex_to_binary(expected_output) << endl; 19 | delete io; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/x86.yml: -------------------------------------------------------------------------------- 1 | name: x86 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build_x86: 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, macos-latest] 9 | build_type: [Debug, Release] 10 | runs-on: ${{ matrix.os }} 11 | timeout-minutes: 30 12 | env: 13 | BUILD_TYPE: ${{matrix.build_type}} 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: install dependency 17 | run: | 18 | wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py 19 | python install.py --install --tool --ot 20 | - name: Create Build Environment 21 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_RANDOM_DEVICE=On && make 22 | - name: Test 23 | shell: bash 24 | run: make test 25 | -------------------------------------------------------------------------------- /lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | cpp: 3 | configure: # Customizable step used only by C/C++ extraction. 4 | command: 5 | - export DEPS_BUILD_DIR=$LGTM_WORKSPACE/deps 6 | - mkdir -p $DEPS_BUILD_DIR 7 | - git clone https://github.com/emp-toolkit/emp-tool.git 8 | - cd emp-tool 9 | - cmake -DENABLE_FLOAT=True -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . 10 | - make -j4 11 | - make install 12 | - git clone https://github.com/emp-toolkit/emp-ot.git 13 | - cd emp-ot 14 | - cmake -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . 15 | - make -j4 16 | - make install 17 | index: # Customizable step used by all languages. 18 | build_command: 19 | - export DEPS_BUILD_DIR=$LGTM_WORKSPACE/deps 20 | - cmake -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . && make 21 | -------------------------------------------------------------------------------- /test/generate_circuit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | void generate_circuit(int n1, int n2, int n3, int C) { 6 | ofstream fout("circuits/"+to_string(n1)+"_"+to_string(n2)+"_"+to_string(n3)+"_"+to_string(C)); 7 | fout< 2 | #include "2pc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH); 7 | int main(int argc, char** argv) { 8 | int port, party; 9 | parse_party_and_port(argv, &party, &port); 10 | 11 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 12 | io->set_nodelay(); 13 | string file = string(argv[3])+"_"+string(argv[4])+"_"+string(argv[5]) +"_"+string(argv[6]); 14 | file = "circuits/"+file; 15 | 16 | CircuitFile cf(file.c_str()); 17 | auto t1 = clock_start(); 18 | C2PC twopc(io, party, &cf); 19 | twopc.function_independent(); 20 | twopc.function_dependent(); 21 | int lenin = party == ALICE ? atoi(argv[3]): atoi(argv[4]); 22 | bool *in = new bool[lenin]; 23 | bool * out = new bool[atoi(argv[5])]; 24 | memset(in, false, lenin); 25 | twopc.online(in, out); 26 | cout << file <<"\t"< 2 | #include "emp-ag2pc/leaky_deltaot.h" 3 | #include 4 | using namespace std; 5 | using namespace emp; 6 | 7 | int size = 1<<20; 8 | 9 | int main(int argc, char** argv) { 10 | int port, party; 11 | parse_party_and_port(argv, &party, &port); 12 | 13 | PRG prg; 14 | NetIO * io = new NetIO(party==ALICE ? nullptr:"127.0.0.1", port); 15 | LeakyDeltaOT *abit = new LeakyDeltaOT(io); 16 | bool delta[128]; 17 | block * t1 = new block[size]; 18 | prg.random_bool(delta, 128); 19 | delta[0] = true; 20 | 21 | if(party == ALICE) 22 | abit->setup_send(delta); 23 | else abit->setup_recv(); 24 | auto tt1 = clock_start(); 25 | if(party == ALICE) { 26 | abit->send_dot(t1, size); 27 | } else { 28 | abit->recv_dot(t1, size); 29 | } 30 | cout << time_from(tt1)<send_block(&(abit->Delta), 1); 35 | io->send_block(t1, size); 36 | } else { 37 | io->recv_block (&Delta, 1); 38 | for(int i = 0; i < size; ++i) { 39 | io->recv_block (&tmp, 1); 40 | if(getLSB(t1[i])) 41 | tmp = tmp ^ Delta; 42 | if(memcmp(&t1[i], &tmp, 16)!=0) 43 | error("check failed!"); 44 | } 45 | } 46 | delete abit; 47 | delete io; 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /emp-ag2pc/leaky_deltaot.h: -------------------------------------------------------------------------------- 1 | #ifndef LEAKY_DELTA_OT_H__ 2 | #define LEAKY_DELTA_OT_H__ 3 | #include 4 | namespace emp { 5 | #ifdef __GNUC__ 6 | #ifndef __clang__ 7 | #pragma GCC push_options 8 | #pragma GCC optimize ("unroll-loops") 9 | #endif 10 | #endif 11 | 12 | template 13 | class LeakyDeltaOT: public IKNP { public: 14 | LeakyDeltaOT(T * io): IKNP(io, false){ 15 | } 16 | 17 | void send_dot(block * data, int length) { 18 | this->send_cot(data, length); 19 | this->io->flush(); 20 | block one = makeBlock(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE); 21 | for (int i = 0; i < length; ++i) { 22 | data[i] = data[i] & one; 23 | } 24 | } 25 | void recv_dot(block* data, int length) { 26 | bool * b = new bool[length]; 27 | this->prg.random_bool(b, length); 28 | this->recv_cot(data, b, length); 29 | this->io->flush(); 30 | 31 | block ch[2]; 32 | ch[0] = zero_block; 33 | ch[1] = makeBlock(0, 1); 34 | block one = makeBlock(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE); 35 | for (int i = 0; i < length; ++i) { 36 | data[i] = (data[i] & one) ^ ch[b[i]]; 37 | } 38 | delete[] b; 39 | } 40 | }; 41 | 42 | #ifdef __GNUC_ 43 | #ifndef __clang___ 44 | #pragma GCC pop_options 45 | #endif 46 | #endif 47 | } 48 | #endif// LEAKY_DELTA_OT_H__ 49 | -------------------------------------------------------------------------------- /emp-ag2pc/feq.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AG2PC_FEQ_H__ 2 | #define EMP_AG2PC_FEQ_H__ 3 | #include 4 | 5 | namespace emp { 6 | 7 | template 8 | class Feq { public: 9 | Hash h; 10 | T* io = nullptr; 11 | int party; 12 | Feq(T* io, int party) { 13 | this->io = io; 14 | this->party = party; 15 | } 16 | void add_block(const block & in) { 17 | h.put(&in, sizeof(block)); 18 | } 19 | 20 | void add_data(const void * data, int len) { 21 | h.put(data, len); 22 | } 23 | 24 | void dgst(char * dgst) { 25 | h.digest(dgst); 26 | } 27 | bool compare() { 28 | char AR[Hash::DIGEST_SIZE+16]; 29 | char dgst[Hash::DIGEST_SIZE]; 30 | h.digest(AR); 31 | if(party == ALICE) { 32 | PRG prg; 33 | prg.random_data(AR+Hash::DIGEST_SIZE, 16); 34 | Hash::hash_once(dgst, AR, Hash::DIGEST_SIZE+16); 35 | io->send_data(dgst, Hash::DIGEST_SIZE); 36 | io->recv_data(dgst, Hash::DIGEST_SIZE); 37 | io->send_data(AR+Hash::DIGEST_SIZE, 16); 38 | } else { 39 | io->recv_data(dgst, Hash::DIGEST_SIZE); 40 | io->send_data(AR, Hash::DIGEST_SIZE); 41 | io->recv_data(AR+Hash::DIGEST_SIZE, 16); 42 | Hash::hash_once(AR, AR, Hash::DIGEST_SIZE+16); 43 | } 44 | io->flush(); 45 | return memcmp(dgst, AR, Hash::DIGEST_SIZE)==0; 46 | } 47 | }; 48 | 49 | } 50 | #endif// FEQ_H__ 51 | -------------------------------------------------------------------------------- /emp-ag2pc/helper.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AG2PC_HELPER_H__ 2 | #define EMP_AG2PC_HELPER_H__ 3 | #include 4 | #include "config.h" 5 | 6 | using std::future; 7 | using std::cout; 8 | using std::endl; 9 | 10 | namespace emp { 11 | 12 | template 13 | void joinNclean(vector>& res) { 14 | for(auto &v: res) v.get(); 15 | res.clear(); 16 | } 17 | 18 | template 19 | void send_partial_block(T * io, const block * data, int length) { 20 | for(int i = 0; i < length; ++i) { 21 | io->send_data(&(data[i]), B); 22 | } 23 | } 24 | 25 | template 26 | void recv_partial_block(T * io, block * data, int length) { 27 | for(int i = 0; i < length; ++i) { 28 | io->recv_data(&(data[i]), B); 29 | } 30 | } 31 | 32 | template 33 | block coin_tossing(PRG prg, T* io, int party) { 34 | block S, S2; 35 | char dgst[Hash::DIGEST_SIZE]; 36 | prg.random_block(&S, 1); 37 | if(party == ALICE) { 38 | Hash::hash_once(dgst, &S, sizeof(block)); 39 | io->send_data(dgst, Hash::DIGEST_SIZE); 40 | io->recv_block(&S2, 1); 41 | io->send_block(&S, 1); 42 | } else { 43 | char dgst2[Hash::DIGEST_SIZE]; 44 | io->recv_data(dgst2, Hash::DIGEST_SIZE); 45 | io->send_block(&S, 1); 46 | io->recv_block(&S2, 1); 47 | Hash::hash_once(dgst, &S2, sizeof(block)); 48 | if (memcmp(dgst, dgst2, Hash::DIGEST_SIZE)!= 0) 49 | error("cheat CT!"); 50 | } 51 | io->flush(); 52 | return S ^ S2; 53 | } 54 | 55 | 56 | } 57 | #endif// __HELPER 58 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | schedule: 9 | - cron: "45 7 * * 5" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ cpp ] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Configure 30 | run: | 31 | export DEPS_BUILD_DIR=$RUNNER_TEMP/deps 32 | mkdir -p $DEPS_BUILD_DIR 33 | git clone https://github.com/emp-toolkit/emp-tool.git 34 | cd emp-tool 35 | cmake -DENABLE_FLOAT=True -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . 36 | make -j4 37 | make install 38 | git clone https://github.com/emp-toolkit/emp-ot.git 39 | cd emp-ot 40 | cmake -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . 41 | make -j4 42 | make install 43 | 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | queries: +security-and-quality 49 | 50 | - name: Build cpp 51 | run: | 52 | export DEPS_BUILD_DIR=$RUNNER_TEMP/deps 53 | cmake -DCMAKE_INSTALL_PREFIX=$DEPS_BUILD_DIR . && make 54 | 55 | - name: Perform CodeQL Analysis 56 | uses: github/codeql-action/analyze@v2 57 | with: 58 | category: "/language:${{ matrix.language }}" 59 | -------------------------------------------------------------------------------- /test/2pc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "2pc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH); 7 | static char out3[] = "92b404e556588ced6c1acd4ebf053f6809f73a93";//bafbc2c87c33322603f38e06c3e0f79c1f1b1475"; 8 | 9 | int main(int argc, char** argv) { 10 | int port, party; 11 | parse_party_and_port(argv, &party, &port); 12 | 13 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 14 | io->set_nodelay(); 15 | string file = circuit_file_location+"/sha-1.txt"; 16 | 17 | CircuitFile cf(file.c_str()); 18 | auto t1 = clock_start(); 19 | C2PC twopc(io, party, &cf); 20 | io->flush(); 21 | cout << "one time:\t"<flush(); 25 | cout << "inde:\t"<flush(); 30 | cout << "dep:\t"< 2 | #include "emp-ag2pc/amortized_2pc.h" 3 | #include "test/single_execution.h" 4 | using namespace std; 5 | using namespace emp; 6 | 7 | static char out3[] = "92b404e556588ced6c1acd4ebf053f6809f73a93";//bafbc2c87c33322603f38e06c3e0f79c1f1b1475"; 8 | const static int runs = 4; 9 | int main(int argc, char** argv) { 10 | int port, party; 11 | parse_party_and_port(argv, &party, &port); 12 | 13 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 14 | // io->set_nodelay(); 15 | string file = "ands.txt";//circuit_file_location+"/AES-non-expanded.txt";//adder_32bit.txt"; 16 | file = circuit_file_location+"/AES-non-expanded.txt";//adder_32bit.txt"; 17 | file = circuit_file_location+"/sha-1.txt"; 18 | 19 | BristolFormat cf(file.c_str()); 20 | 21 | auto t1 = clock_start(); 22 | AmortizedC2PC twopc(io, party, &cf); 23 | io->flush(); 24 | cout << "one time:\t"<flush(); 28 | cout << "inde:\t"<flush(); 33 | cout << "dep:\t"< 8 | 9 | Authenticated Garbling and Efficient Maliciously Secure Two-Party Computation. More details of the protocol can be found in the [paper](https://eprint.iacr.org/2017/030). 10 | 11 | # Installation 12 | 1. `wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py` 13 | 2. `python install.py --install --tool --ot --ag2pc` 14 | 1. By default it will build for Release. `-DCMAKE_BUILD_TYPE=[Release|Debug]` option is also available. 15 | 2. No sudo? Change [`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/v2.8.8/cmake.html#variable%3aCMAKE_INSTALL_PREFIX). 16 | 17 | 18 | ## Test 19 | 20 | * If you want to test the code in local machine, type 21 | 22 | `./run ./bin/[binaries] 12345 [more opts]` 23 | * IF you want to test the code over two machine, type 24 | 25 | `./bin/[binaries] 1 12345 [more opts]` on one machine and 26 | 27 | `./bin/[binaries] 2 12345 [more opts]` on the other. 28 | 29 | IP address is hardcoded in the test files. Please replace 30 | IP variable to the real ip. 31 | 32 | ### Question 33 | Please send email to wangxiao1254@gmail.com 34 | 35 | ## Acknowledgement 36 | This work was supported in part by the National Science Foundation under Awards #1111599 and #1563722. 37 | -------------------------------------------------------------------------------- /test/amortized_2pc2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "amortized_2pc.h" 3 | using namespace std; 4 | using namespace emp; 5 | double get_io_count(Fpre * fpre, NetIO * io) { 6 | double res = 0; 7 | #ifdef COUNT_IO 8 | for(int i = 0; i < fpre->THDS; ++i) { 9 | res += fpre->io[i]->counter; 10 | res += fpre->io2[i]->counter; 11 | } 12 | res += io->counter; 13 | #endif 14 | return res; 15 | } 16 | 17 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH); 18 | const static int runs = 128; 19 | int main(int argc, char** argv) { 20 | int port, party; 21 | parse_party_and_port(argv, &party, &port); 22 | 23 | NetIO* io = new NetIO(party==ALICE ? nullptr:IP, port); 24 | io->set_nodelay(); 25 | string file = "ands.txt";//circuit_file_location+"/AES-non-expanded.txt";//adder_32bit.txt"; 26 | file = circuit_file_location+"/AES-non-expanded.txt";//adder_32bit.txt"; 27 | // file = circuit_file_location+"/sha-256.txt"; 28 | 29 | CircuitFile cf(file.c_str()); 30 | 31 | auto t1 = clock_start(); 32 | AmortizedC2PC twopc(io, party, &cf); 33 | io->flush(); 34 | cout << "one time:\t"<flush(); 38 | cout << "inde:\t"<flush(); 45 | cout << "dep:\t"< 2 | #include "emp-ag2pc/emp-ag2pc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | inline const char* hex_char_to_bin(char c) { 7 | switch(toupper(c)) { 8 | case '0': return "0000"; 9 | case '1': return "0001"; 10 | case '2': return "0010"; 11 | case '3': return "0011"; 12 | case '4': return "0100"; 13 | case '5': return "0101"; 14 | case '6': return "0110"; 15 | case '7': return "0111"; 16 | case '8': return "1000"; 17 | case '9': return "1001"; 18 | case 'A': return "1010"; 19 | case 'B': return "1011"; 20 | case 'C': return "1100"; 21 | case 'D': return "1101"; 22 | case 'E': return "1110"; 23 | case 'F': return "1111"; 24 | default: return "0"; 25 | } 26 | } 27 | 28 | inline std::string hex_to_binary(std::string hex) { 29 | std::string bin; 30 | for(unsigned i = 0; i != hex.length(); ++i) 31 | bin += hex_char_to_bin(hex[i]); 32 | return bin; 33 | } 34 | 35 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH)+string("bristol_format/"); 36 | 37 | template 38 | void test(int party, T* io, string name, string check_output = "", string hin = "") { 39 | //string file = circuit_file_location + name; 40 | string file = name; 41 | BristolFormat cf(file.c_str()); 42 | auto t1 = clock_start(); 43 | C2PC twopc(io, party, &cf); 44 | io->flush(); 45 | cout << "one time:\t"<flush(); 50 | cout << "inde:\t"<flush(); 55 | cout << "dep:\t"< 0) { 62 | string bin = hex_to_binary(hin); 63 | for (int i=0; i < cf.n1 + cf.n2; ++i) { 64 | if (bin[i] == '0') 65 | in[i] = false; 66 | else if (bin[i] == '1') 67 | in[i] = true; 68 | else { 69 | cout << "problem: " << bin[i] << endl; 70 | exit(1); 71 | } 72 | } 73 | } else { 74 | memset(in, false, cf.n1 + cf.n2); 75 | } 76 | memset(out, false, cf.n3); 77 | t1 = clock_start(); 78 | twopc.online(in, out, true); 79 | cout << "online:\t"< 0){ 85 | string res = ""; 86 | for(int i = 0; i < cf.n3; ++i) 87 | res += (out[i]?"1":"0"); 88 | cout << (res == hex_to_binary(check_output)? "GOOD!":"BAD!")< 4 | #include 5 | #include 6 | #include "emp-ag2pc/feq.h" 7 | #include "emp-ag2pc/helper.h" 8 | #include "emp-ag2pc/leaky_deltaot.h" 9 | #include "emp-ag2pc/config.h" 10 | 11 | namespace emp { 12 | //#define __debug 13 | 14 | template 15 | class Fpre { 16 | public: 17 | ThreadPool *pool; 18 | const static int THDS = fpre_threads; 19 | int batch_size = 0, bucket_size = 0, size = 0; 20 | int party; 21 | block * keys = nullptr; 22 | bool * values = nullptr; 23 | PRG prg; 24 | PRP prp; 25 | PRP *prps; 26 | T *io[THDS]; 27 | T *io2[THDS]; 28 | int bandwidth() { 29 | int sum = 0; 30 | for(int i = 0; i < THDS; ++i) { 31 | sum+=io[i]->counter; 32 | sum+=io2[i]->counter; 33 | } 34 | return sum; 35 | } 36 | LeakyDeltaOT *abit1[THDS], *abit2[THDS]; 37 | block Delta; 38 | block ZDelta; 39 | block one; 40 | Feq *eq[THDS*2]; 41 | block * MAC = nullptr, *KEY = nullptr; 42 | block * MAC_res = nullptr, *KEY_res = nullptr; 43 | block * pretable = nullptr; 44 | Fpre(T * in_io, int in_party, int bsize = 1000) { 45 | pool = new ThreadPool(THDS*2); 46 | prps = new PRP[THDS*2]; 47 | this->party = in_party; 48 | for(int i = 0; i < THDS; ++i) { 49 | usleep(1000); 50 | io[i] = new T(in_io->is_server?nullptr:in_io->addr.c_str(), in_io->port, true); 51 | usleep(1000); 52 | io2[i] = new T(in_io->is_server?nullptr:in_io->addr.c_str(), in_io->port, true); 53 | eq[i] = new Feq(io[i], party); 54 | eq[THDS+i] = new Feq(io2[i], party); 55 | } 56 | 57 | abit1[0] = new LeakyDeltaOT(io[0]); 58 | abit2[0] = new LeakyDeltaOT(io2[0]); 59 | 60 | bool tmp_s[128]; 61 | prg.random_bool(tmp_s, 128); 62 | tmp_s[0] = true; 63 | if(party == ALICE) { 64 | tmp_s[1] = true; 65 | abit1[0]->setup_send(tmp_s); 66 | io[0]->flush(); 67 | abit2[0]->setup_recv(); 68 | } else { 69 | tmp_s[1] = false; 70 | abit1[0]->setup_recv(); 71 | io[0]->flush(); 72 | abit2[0]->setup_send(tmp_s); 73 | } 74 | io2[0]->flush(); 75 | for(int i = 1; i < THDS; ++i) { 76 | abit1[i] = new LeakyDeltaOT(io[i]); 77 | abit2[i] = new LeakyDeltaOT(io2[i]); 78 | if(party == ALICE) { 79 | abit1[i]->setup_send(tmp_s, abit1[0]->k0); 80 | abit2[i]->setup_recv(abit2[0]->k0, abit2[0]->k1); 81 | } else { 82 | abit2[i]->setup_send(tmp_s, abit2[0]->k0); 83 | abit1[i]->setup_recv(abit1[0]->k0, abit1[0]->k1); 84 | } 85 | } 86 | 87 | if(party == ALICE) Delta = abit1[0]->Delta; 88 | else Delta = abit2[0]->Delta; 89 | one = makeBlock(0, 1); 90 | ZDelta = Delta & makeBlock(0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFE); 91 | set_batch_size(bsize); 92 | } 93 | int permute_batch_size; 94 | void set_batch_size(int size) { 95 | size = std::max(size, 320); 96 | batch_size = ((size+THDS*2-1)/(2*THDS))*THDS*2; 97 | if(batch_size >= 280*1000) { 98 | bucket_size = 3; 99 | permute_batch_size = 280000; 100 | } 101 | else if(batch_size >= 3100) { 102 | bucket_size = 4; 103 | permute_batch_size = 3100; 104 | } 105 | else bucket_size = 5; 106 | 107 | delete[] MAC; 108 | delete[] KEY; 109 | 110 | MAC = new block[batch_size * bucket_size * 3]; 111 | KEY = new block[batch_size * bucket_size * 3]; 112 | MAC_res = new block[batch_size * 3]; 113 | KEY_res = new block[batch_size * 3]; 114 | // cout << size<<"\t"<> res; 136 | for(int i = 0; i < THDS; ++i) { 137 | int start = i*(batch_size/THDS); 138 | int length = batch_size/THDS; 139 | res.push_back(pool->enqueue([this, start, length, i](){ 140 | generate(MAC + start * bucket_size*3, KEY + start * bucket_size*3, length * bucket_size, i); 141 | })); 142 | } 143 | joinNclean(res); 144 | 145 | if(party == ALICE) { 146 | cout <<"ABIT\t"<enqueue([this, start, length, i](){ 155 | check(MAC + start * bucket_size*3, KEY + start * bucket_size*3, length * bucket_size, i); 156 | })); 157 | } 158 | joinNclean(res); 159 | if(party == ALICE) { 160 | cout <<"check\t"< 4) { 169 | combine(S, 0, MAC, KEY, batch_size, bucket_size, MAC_res, KEY_res); 170 | } else { 171 | int width = min((batch_size+THDS-1)/THDS, permute_batch_size); 172 | for(int i = 0; i < THDS; ++i) { 173 | int start = i*width; 174 | int length = min( (i+1)*width, batch_size) - i*width; 175 | res.push_back(pool->enqueue([this, start, length, i, S](){ 176 | combine(S, i, MAC+start*bucket_size*3, KEY+start*bucket_size*3, length, bucket_size, MAC_res+start*3, KEY_res+start*3); 177 | })); 178 | } 179 | joinNclean(res); 180 | } 181 | if(party == ALICE) { 182 | cout <<"permute\t"<dgst(dgst); 192 | eq[0]->add_data(dgst, Hash::DIGEST_SIZE); 193 | } 194 | if(!eq[0]->compare()) { 195 | error("FEQ error\n"); 196 | } 197 | } 198 | 199 | void generate(block * MAC, block * KEY, int length, int I) { 200 | if (party == ALICE) { 201 | future fut = pool->enqueue([this, length, KEY, I](){ 202 | abit1[I]->send_dot(KEY, length*3); 203 | }); 204 | abit2[I]->recv_dot(MAC, length*3); 205 | fut.get(); 206 | } else { 207 | future fut = pool->enqueue([this, length, KEY, I](){ 208 | abit2[I]->send_dot(KEY, length*3); 209 | }); 210 | abit1[I]->recv_dot(MAC, length*3); 211 | fut.get(); 212 | } 213 | } 214 | 215 | void check(block * MAC, block * KEY, int length, int I) { 216 | T * local_io = (I%2==0) ? io[I/2]: io2[I/2]; 217 | 218 | block * G = new block[length]; 219 | block * C = new block[length]; 220 | block * GR = new block[length]; 221 | bool * d = new bool[length]; 222 | bool * dR = new bool[length]; 223 | 224 | for (int i = 0; i < length; ++i) { 225 | C[i] = KEY[3*i+1] ^ MAC[3*i+1]; 226 | C[i] = C[i] ^ (select_mask[getLSB(MAC[3*i+1])] & Delta); 227 | G[i] = H2D(KEY[3*i], Delta, I); 228 | G[i] = G[i] ^ C[i]; 229 | } 230 | if(party == ALICE) { 231 | local_io->send_data(G, sizeof(block)*length); 232 | local_io->recv_data(GR, sizeof(block)*length); 233 | } else { 234 | local_io->recv_data(GR, sizeof(block)*length); 235 | local_io->send_data(G, sizeof(block)*length); 236 | } 237 | local_io->flush(); 238 | for(int i = 0; i < length; ++i) { 239 | block S = H2(MAC[3*i], KEY[3*i], I); 240 | S = S ^ MAC[3*i+2] ^ KEY[3*i+2]; 241 | S = S ^ (select_mask[getLSB(MAC[3*i])] & (GR[i] ^ C[i])); 242 | G[i] = S ^ (select_mask[getLSB(MAC[3*i+2])] & Delta); 243 | d[i] = getL2SB(G[i]); 244 | } 245 | 246 | if(party == ALICE) { 247 | local_io->send_bool(d, length); 248 | local_io->recv_bool(dR,length); 249 | } else { 250 | local_io->recv_bool(dR, length); 251 | local_io->send_bool(d, length); 252 | } 253 | local_io->flush(); 254 | for(int i = 0; i < length; ++i) { 255 | d[i] = d[i] != dR[i]; 256 | if (d[i]) { 257 | if(party == ALICE) 258 | MAC[3*i+2] = MAC[3*i+2] ^ one; 259 | else 260 | KEY[3*i+2] = KEY[3*i+2] ^ ZDelta; 261 | 262 | G[i] = G[i] ^ Delta; 263 | } 264 | eq[I]->add_block(G[i]); 265 | } 266 | delete[] G; 267 | delete[] GR; 268 | delete[] C; 269 | delete[] d; 270 | delete[] dR; 271 | } 272 | block H2D(block a, block b, int I) { 273 | block d[2]; 274 | d[0] = a; 275 | d[1] = a ^ b; 276 | prps[I].permute_block(d, 2); 277 | d[0] = d[0] ^ d[1]; 278 | return d[0] ^ b; 279 | } 280 | 281 | block H2(block a, block b, int I) { 282 | block d[2]; 283 | d[0] = a; 284 | d[1] = b; 285 | prps[I].permute_block(d, 2); 286 | d[0] = d[0] ^ d[1]; 287 | d[0] = d[0] ^ a; 288 | return d[0] ^ b; 289 | } 290 | 291 | bool getL2SB(block b) { 292 | unsigned char x = *((unsigned char*)&b); 293 | return ((x >> 1) & 0x1) == 1; 294 | } 295 | 296 | void combine(block S, int I, block * MAC, block * KEY, int length, int bucket_size, block * MAC_res, block * KEY_res) { 297 | int *location = new int[length*bucket_size]; 298 | for(int i = 0; i < length*bucket_size; ++i) location[i] = i; 299 | PRG prg(&S, I); 300 | int * ind = new int[length*bucket_size]; 301 | prg.random_data(ind, length*bucket_size*4); 302 | for(int i = length*bucket_size-1; i>=0; --i) { 303 | int index = ind[i]%(i+1); 304 | index = index>0? index:(-1*index); 305 | int tmp = location[i]; 306 | location[i] = location[index]; 307 | location[index] = tmp; 308 | } 309 | delete[] ind; 310 | 311 | bool *data = new bool[length*bucket_size]; 312 | bool *data2 = new bool[length*bucket_size]; 313 | for(int i = 0; i < length; ++i) { 314 | for(int j = 1; j < bucket_size; ++j) { 315 | data[i*bucket_size+j] = getLSB(MAC[location[i*bucket_size]*3+1] ^ MAC[location[i*bucket_size+j]*3+1]); 316 | } 317 | } 318 | if(party == ALICE) { 319 | io[I]->send_bool(data, length*bucket_size); 320 | io[I]->recv_bool(data2, length*bucket_size); 321 | } else { 322 | io[I]->recv_bool(data2, length*bucket_size); 323 | io[I]->send_bool(data, length*bucket_size); 324 | } 325 | io[I]->flush(); 326 | for(int i = 0; i < length; ++i) { 327 | for(int j = 1; j < bucket_size; ++j) { 328 | data[i*bucket_size+j] = (data[i*bucket_size+j] != data2[i*bucket_size+j]); 329 | } 330 | } 331 | for(int i = 0; i < length; ++i) { 332 | for(int j = 0; j < 3; ++j) { 333 | MAC_res[i*3+j] = MAC[location[i*bucket_size]*3+j]; 334 | KEY_res[i*3+j] = KEY[location[i*bucket_size]*3+j]; 335 | } 336 | for(int j = 1; j < bucket_size; ++j) { 337 | MAC_res[3*i] = MAC_res[3*i] ^ MAC[location[i*bucket_size+j]*3]; 338 | KEY_res[3*i] = KEY_res[3*i] ^ KEY[location[i*bucket_size+j]*3]; 339 | 340 | MAC_res[i*3+2] = MAC_res[i*3+2] ^ MAC[location[i*bucket_size+j]*3+2]; 341 | KEY_res[i*3+2] = KEY_res[i*3+2] ^ KEY[location[i*bucket_size+j]*3+2]; 342 | 343 | if(data[i*bucket_size+j]) { 344 | KEY_res[i*3+2] = KEY_res[i*3+2] ^ KEY[location[i*bucket_size+j]*3]; 345 | MAC_res[i*3+2] = MAC_res[i*3+2] ^ MAC[location[i*bucket_size+j]*3]; 346 | } 347 | } 348 | } 349 | 350 | delete[] data; 351 | delete[] location; 352 | delete[] data2; 353 | } 354 | 355 | //for debug 356 | void check_correctness(block * MAC, block * KEY, int length) { 357 | if (party == ALICE) { 358 | for(int i = 0; i < length*3; ++i) { 359 | bool tmp = getLSB(MAC[i]); 360 | io[0]->send_data(&tmp, 1); 361 | } 362 | io[0]->send_block(&Delta, 1); 363 | io[0]->send_block(KEY, length*3); 364 | block DD;io[0]->recv_block(&DD, 1); 365 | 366 | for(int i = 0; i < length*3; ++i) { 367 | block tmp;io[0]->recv_block(&tmp, 1); 368 | if(getLSB(MAC[i])) tmp = tmp ^ DD; 369 | if (!cmpBlock(&tmp, &MAC[i], 1)) 370 | cout <recv_data(tmp, 3); 377 | bool res = ((tmp[0] != getLSB(MAC[3*i]) ) && (tmp[1] != getLSB(MAC[3*i+1]))); 378 | if(res != (tmp[2] != getLSB(MAC[3*i+2])) ) { 379 | cout <recv_block(&DD, 1); 383 | 384 | for(int i = 0; i < length*3; ++i) { 385 | block tmp;io[0]->recv_block(&tmp, 1); 386 | if(getLSB(MAC[i])) tmp = tmp ^ DD; 387 | if (!cmpBlock(&tmp, &MAC[i], 1)) 388 | cout <send_block(&Delta, 1); 392 | io[0]->send_block(KEY, length*3); 393 | } 394 | io[0]->flush(); 395 | } 396 | }; 397 | } 398 | #endif// FPRE_H__ 399 | -------------------------------------------------------------------------------- /emp-ag2pc/2pc.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AG2PC_2PC_H__ 2 | #define EMP_AG2PC_2PC_H__ 3 | #include 4 | #include "emp-ag2pc/fpre.h" 5 | 6 | namespace emp { 7 | template 8 | class C2PC { public: 9 | const static int SSP = 5;//5*8 in fact... 10 | const block MASK = makeBlock(0x0ULL, 0xFFFFFULL); 11 | Fpre* fpre = nullptr; 12 | block * mac = nullptr; 13 | block * key = nullptr; 14 | 15 | block * preprocess_mac = nullptr; 16 | block * preprocess_key = nullptr; 17 | 18 | block * sigma_mac = nullptr; 19 | block * sigma_key = nullptr; 20 | 21 | block * labels = nullptr; 22 | 23 | bool * mask = nullptr; 24 | BristolFormat * cf; 25 | T * io; 26 | int num_ands = 0; 27 | int party, total_pre; 28 | C2PC(T * io, int party, BristolFormat * cf) { 29 | this->party = party; 30 | this->io = io; 31 | this->cf = cf; 32 | for(int i = 0; i < cf->num_gate; ++i) { 33 | if (cf->gates[4*i+3] == AND_GATE) 34 | ++num_ands; 35 | } 36 | cout << cf->n1<<" "<n2<<" "<n3<<" "<n1 + cf->n2 + num_ands; 38 | fpre = new Fpre(io, party, num_ands); 39 | 40 | key = new block[cf->num_wire]; 41 | mac = new block[cf->num_wire]; 42 | 43 | preprocess_mac = new block[total_pre]; 44 | preprocess_key = new block[total_pre]; 45 | 46 | //sigma values in the paper 47 | sigma_mac = new block[num_ands]; 48 | sigma_key = new block[num_ands]; 49 | 50 | labels = new block[cf->num_wire]; 51 | 52 | mask = new bool[cf->n1 + cf->n2]; 53 | } 54 | ~C2PC(){ 55 | delete[] key; 56 | delete[] mac; 57 | delete[] mask; 58 | delete[] GT; 59 | delete[] GTK; 60 | delete[] GTM; 61 | 62 | delete[] preprocess_mac; 63 | delete[] preprocess_key; 64 | 65 | delete[] sigma_mac; 66 | delete[] sigma_key; 67 | 68 | delete[] labels; 69 | delete fpre; 70 | } 71 | PRG prg; 72 | PRP prp; 73 | block (* GT)[4][2] = nullptr; 74 | block (* GTK)[4] = nullptr; 75 | block (* GTM)[4] = nullptr; 76 | 77 | //not allocation 78 | block * ANDS_mac = nullptr; 79 | block * ANDS_key = nullptr; 80 | void function_independent() { 81 | if(party == ALICE) 82 | prg.random_block(labels, cf->num_wire); 83 | 84 | fpre->refill(); 85 | ANDS_mac = fpre->MAC_res; 86 | ANDS_key = fpre->KEY_res; 87 | 88 | if(fpre->party == ALICE) { 89 | fpre->abit1[0]->send_dot(preprocess_key, total_pre); 90 | fpre->abit2[0]->recv_dot(preprocess_mac, total_pre); 91 | } else { 92 | fpre->abit1[0]->recv_dot(preprocess_mac, total_pre); 93 | fpre->abit2[0]->send_dot(preprocess_key, total_pre); 94 | } 95 | memcpy(key, preprocess_key, (cf->n1+cf->n2)*sizeof(block)); 96 | memcpy(mac, preprocess_mac, (cf->n1+cf->n2)*sizeof(block)); 97 | } 98 | 99 | void function_dependent() { 100 | int ands = cf->n1+cf->n2; 101 | bool * x1 = new bool[num_ands]; 102 | bool * y1 = new bool[num_ands]; 103 | bool * x2 = new bool[num_ands]; 104 | bool * y2 = new bool[num_ands]; 105 | 106 | for(int i = 0; i < cf->num_gate; ++i) { 107 | if (cf->gates[4*i+3] == AND_GATE) { 108 | key[cf->gates[4*i+2]] = preprocess_key[ands]; 109 | mac[cf->gates[4*i+2]] = preprocess_mac[ands]; 110 | ++ands; 111 | } 112 | } 113 | 114 | for(int i = 0; i < cf->num_gate; ++i) { 115 | if (cf->gates[4*i+3] == XOR_GATE) { 116 | key[cf->gates[4*i+2]] = key[cf->gates[4*i]] ^ key[cf->gates[4*i+1]]; 117 | mac[cf->gates[4*i+2]] = mac[cf->gates[4*i]] ^ mac[cf->gates[4*i+1]]; 118 | if(party == ALICE) 119 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]] ^ labels[cf->gates[4*i+1]]; 120 | } else if (cf->gates[4*i+3] == NOT_GATE) { 121 | if(party == ALICE) 122 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]] ^ fpre->Delta; 123 | key[cf->gates[4*i+2]] = key[cf->gates[4*i]]; 124 | mac[cf->gates[4*i+2]] = mac[cf->gates[4*i]]; 125 | } 126 | } 127 | 128 | ands = 0; 129 | for(int i = 0; i < cf->num_gate; ++i) { 130 | if (cf->gates[4*i+3] == AND_GATE) { 131 | x1[ands] = getLSB(mac[cf->gates[4*i]] ^ANDS_mac[3*ands]); 132 | y1[ands] = getLSB(mac[cf->gates[4*i+1]]^ANDS_mac[3*ands+1]); 133 | ands++; 134 | } 135 | } 136 | if(party == ALICE) { 137 | io->send_bool(x1, num_ands); 138 | io->send_bool(y1, num_ands); 139 | io->recv_bool(x2, num_ands); 140 | io->recv_bool(y2, num_ands); 141 | } else { 142 | io->recv_bool(x2, num_ands); 143 | io->recv_bool(y2, num_ands); 144 | io->send_bool(x1, num_ands); 145 | io->send_bool(y1, num_ands); 146 | } 147 | io->flush(); 148 | for(int i = 0; i < num_ands; ++i) { 149 | x1[i] = logic_xor(x1[i], x2[i]); 150 | y1[i] = logic_xor(y1[i], y2[i]); 151 | } 152 | ands = 0; 153 | for(int i = 0; i < cf->num_gate; ++i) { 154 | if (cf->gates[4*i+3] == AND_GATE) { 155 | sigma_mac[ands] = ANDS_mac[3*ands+2]; 156 | sigma_key[ands] = ANDS_key[3*ands+2]; 157 | 158 | if(x1[ands]) { 159 | sigma_mac[ands] = sigma_mac[ands] ^ ANDS_mac[3*ands+1]; 160 | sigma_key[ands] = sigma_key[ands] ^ ANDS_key[3*ands+1]; 161 | } 162 | if(y1[ands]) { 163 | sigma_mac[ands] = sigma_mac[ands] ^ ANDS_mac[3*ands]; 164 | sigma_key[ands] = sigma_key[ands] ^ ANDS_key[3*ands]; 165 | } 166 | if(x1[ands] and y1[ands]) { 167 | if(party == ALICE) 168 | sigma_key[ands] = sigma_key[ands] ^ fpre->ZDelta; 169 | else 170 | sigma_mac[ands] = sigma_mac[ands] ^ fpre->one; 171 | } 172 | 173 | ands++; 174 | } 175 | }//sigma_[] stores the and of input wires to each AND gates 176 | 177 | delete[] fpre->MAC; 178 | delete[] fpre->KEY; 179 | fpre->MAC = nullptr; 180 | fpre->KEY = nullptr; 181 | GT = new block[num_ands][4][2]; 182 | GTK = new block[num_ands][4]; 183 | GTM = new block[num_ands][4]; 184 | 185 | ands = 0; 186 | block H[4][2]; 187 | block K[4], M[4]; 188 | for(int i = 0; i < cf->num_gate; ++i) { 189 | if(cf->gates[4*i+3] == AND_GATE) { 190 | M[0] = sigma_mac[ands] ^ mac[cf->gates[4*i+2]]; 191 | M[1] = M[0] ^ mac[cf->gates[4*i]]; 192 | M[2] = M[0] ^ mac[cf->gates[4*i+1]]; 193 | M[3] = M[1] ^ mac[cf->gates[4*i+1]]; 194 | if(party == BOB) 195 | M[3] = M[3] ^ fpre->one; 196 | 197 | K[0] = sigma_key[ands] ^ key[cf->gates[4*i+2]]; 198 | K[1] = K[0] ^ key[cf->gates[4*i]]; 199 | K[2] = K[0] ^ key[cf->gates[4*i+1]]; 200 | K[3] = K[1] ^ key[cf->gates[4*i+1]]; 201 | if(party == ALICE) 202 | K[3] = K[3] ^ fpre->ZDelta; 203 | 204 | if(party == ALICE) { 205 | Hash(H, labels[cf->gates[4*i]], labels[cf->gates[4*i+1]], i); 206 | for(int j = 0; j < 4; ++j) { 207 | H[j][0] = H[j][0] ^ M[j]; 208 | H[j][1] = H[j][1] ^ K[j] ^ labels[cf->gates[4*i+2]]; 209 | if(getLSB(M[j])) 210 | H[j][1] = H[j][1] ^fpre->Delta; 211 | #ifdef __debug 212 | check2(M[j], K[j]); 213 | #endif 214 | } 215 | for(int j = 0; j < 4; ++j ) { 216 | send_partial_block(io, &H[j][0], 1); 217 | io->send_block(&H[j][1], 1); 218 | } 219 | } else { 220 | memcpy(GTK[ands], K, sizeof(block)*4); 221 | memcpy(GTM[ands], M, sizeof(block)*4); 222 | #ifdef __debug 223 | for(int j = 0; j < 4; ++j) 224 | check2(M[j], K[j]); 225 | #endif 226 | for(int j = 0; j < 4; ++j ) { 227 | recv_partial_block(io, >[ands][j][0], 1); 228 | io->recv_block(>[ands][j][1], 1); 229 | } 230 | } 231 | ++ands; 232 | } 233 | } 234 | delete[] x1; 235 | delete[] x2; 236 | delete[] y1; 237 | delete[] y2; 238 | 239 | block tmp; 240 | if(party == ALICE) { 241 | send_partial_block(io, mac, cf->n1); 242 | for(int i = cf->n1; i < cf->n1+cf->n2; ++i) { 243 | recv_partial_block(io, &tmp, 1); 244 | block ttt = key[i] ^ fpre->Delta; 245 | ttt = ttt & MASK; 246 | block mask_key = key[i] & MASK; 247 | tmp = tmp & MASK; 248 | if(cmpBlock(&tmp, &mask_key, 1)) 249 | mask[i] = false; 250 | else if(cmpBlock(&tmp, &ttt, 1)) 251 | mask[i] = true; 252 | else cout <<"no match! ALICE\t"<n1; ++i) { 256 | recv_partial_block(io, &tmp, 1); 257 | block ttt = key[i] ^ fpre->Delta; 258 | ttt = ttt & MASK; 259 | tmp = tmp & MASK; 260 | block mask_key = key[i] & MASK; 261 | if(cmpBlock(&tmp, &mask_key, 1)) { 262 | mask[i] = false; 263 | } else if(cmpBlock(&tmp, &ttt, 1)) { 264 | mask[i] = true; 265 | } 266 | else cout <<"no match! BOB\t"<(io, mac+cf->n1, cf->n2); 270 | } 271 | io->flush(); 272 | } 273 | 274 | void online (const bool * input, bool * output, bool alice_output = false) { 275 | uint8_t * mask_input = new uint8_t[cf->num_wire]; 276 | memset(mask_input, 0, cf->num_wire); 277 | block tmp; 278 | #ifdef __debug 279 | for(int i = 0; i < cf->n1+cf->n2; ++i) 280 | check2(mac[i], key[i]); 281 | #endif 282 | if(party == ALICE) { 283 | for(int i = cf->n1; i < cf->n1+cf->n2; ++i) { 284 | mask_input[i] = logic_xor(input[i], getLSB(mac[i])); 285 | mask_input[i] = logic_xor(mask_input[i], mask[i]); 286 | } 287 | io->recv_data(mask_input, cf->n1); 288 | io->send_data(mask_input+cf->n1, cf->n2); 289 | for(int i = 0; i < cf->n1 + cf->n2; ++i) { 290 | tmp = labels[i]; 291 | if(mask_input[i]) tmp = tmp ^ fpre->Delta; 292 | io->send_block(&tmp, 1); 293 | } 294 | //send output mask data 295 | send_partial_block(io, mac+cf->num_wire - cf->n3, cf->n3); 296 | } else { 297 | for(int i = 0; i < cf->n1; ++i) { 298 | mask_input[i] = logic_xor(input[i], getLSB(mac[i])); 299 | mask_input[i] = logic_xor(mask_input[i], mask[i]); 300 | } 301 | io->send_data(mask_input, cf->n1); 302 | io->recv_data(mask_input+cf->n1, cf->n2); 303 | io->recv_block(labels, cf->n1 + cf->n2); 304 | } 305 | int ands = 0; 306 | if(party == BOB) { 307 | for(int i = 0; i < cf->num_gate; ++i) { 308 | if (cf->gates[4*i+3] == XOR_GATE) { 309 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]] ^ labels[cf->gates[4*i+1]]; 310 | mask_input[cf->gates[4*i+2]] = logic_xor(mask_input[cf->gates[4*i]], mask_input[cf->gates[4*i+1]]); 311 | } else if (cf->gates[4*i+3] == AND_GATE) { 312 | int index = 2*mask_input[cf->gates[4*i]] + mask_input[cf->gates[4*i+1]]; 313 | block H[2]; 314 | Hash(H, labels[cf->gates[4*i]], labels[cf->gates[4*i+1]], i, index); 315 | GT[ands][index][0] = GT[ands][index][0] ^ H[0]; 316 | GT[ands][index][1] = GT[ands][index][1] ^ H[1]; 317 | 318 | block ttt = GTK[ands][index] ^ fpre->Delta; 319 | ttt = ttt & MASK; 320 | GTK[ands][index] = GTK[ands][index] & MASK; 321 | GT[ands][index][0] = GT[ands][index][0] & MASK; 322 | 323 | if(cmpBlock(>[ands][index][0], >K[ands][index], 1)) 324 | mask_input[cf->gates[4*i+2]] = false; 325 | else if(cmpBlock(>[ands][index][0], &ttt, 1)) 326 | mask_input[cf->gates[4*i+2]] = true; 327 | else cout <gates[4*i+2]] = logic_xor(mask_input[cf->gates[4*i+2]], getLSB(GTM[ands][index])); 329 | 330 | labels[cf->gates[4*i+2]] = GT[ands][index][1] ^ GTM[ands][index]; 331 | ands++; 332 | } else { 333 | mask_input[cf->gates[4*i+2]] = not mask_input[cf->gates[4*i]]; 334 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]]; 335 | } 336 | } 337 | } 338 | if (party == BOB) { 339 | bool * o = new bool[cf->n3]; 340 | for(int i = 0; i < cf->n3; ++i) { 341 | block tmp; 342 | recv_partial_block(io, &tmp, 1); 343 | tmp = tmp & MASK; 344 | 345 | block ttt = key[cf->num_wire - cf-> n3 + i] ^ fpre->Delta; 346 | ttt = ttt & MASK; 347 | key[cf->num_wire - cf-> n3 + i] = key[cf->num_wire - cf-> n3 + i] & MASK; 348 | 349 | if(cmpBlock(&tmp, &key[cf->num_wire - cf-> n3 + i], 1)) 350 | o[i] = false; 351 | else if(cmpBlock(&tmp, &ttt, 1)) 352 | o[i] = true; 353 | else cout <<"no match output label!"<n3; ++i) { 356 | output[i] = logic_xor(o[i], mask_input[cf->num_wire - cf->n3 + i]); 357 | output[i] = logic_xor(output[i], getLSB(mac[cf->num_wire - cf->n3 + i])); 358 | } 359 | delete[] o; 360 | if(alice_output) { 361 | send_partial_block(io, mac+cf->num_wire - cf->n3, cf->n3); 362 | send_partial_block(io, labels+cf->num_wire - cf->n3, cf->n3); 363 | io->send_data(mask_input + cf->num_wire - cf->n3, cf->n3); 364 | io->flush(); 365 | } 366 | } else {//ALICE 367 | if(alice_output) { 368 | block * tmp_mac = new block[cf->n3]; 369 | block * tmp_label = new block[cf->n3]; 370 | bool * tmp_mask_input = new bool[cf->n3]; 371 | recv_partial_block(io, tmp_mac, cf->n3); 372 | recv_partial_block(io, tmp_label, cf->n3); 373 | io->recv_data(tmp_mask_input, cf->n3); 374 | io->flush(); 375 | for(int i = 0; i < cf->n3; ++i) { 376 | block tmp = tmp_mac[i]; 377 | tmp = tmp & MASK; 378 | 379 | block ttt = key[cf->num_wire - cf-> n3 + i] ^ fpre->Delta; 380 | ttt = ttt & MASK; 381 | key[cf->num_wire - cf-> n3 + i] = key[cf->num_wire - cf-> n3 + i] & MASK; 382 | 383 | if(cmpBlock(&tmp, &key[cf->num_wire - cf-> n3 + i], 1)) 384 | output[i] = false; 385 | else if(cmpBlock(&tmp, &ttt, 1)) 386 | output[i] = true; 387 | else cout <<"no match output label!"<Delta; 391 | mask_label = mask_label & MASK; 392 | block masked_labels = labels[cf->num_wire - cf-> n3 + i] & MASK; 393 | if(!cmpBlock(&mask_label, &masked_labels, 1)) 394 | cout <<"no match output label2!"<num_wire - cf->n3 + i])); 398 | } 399 | delete[] tmp_mac; 400 | delete[] tmp_label; 401 | delete[] tmp_mask_input; 402 | } 403 | 404 | } 405 | delete[] mask_input; 406 | } 407 | 408 | void check(block * MAC, block * KEY, bool * r, int length = 1) { 409 | if (party == ALICE) { 410 | io->send_data(r, length*3); 411 | io->send_block(&fpre->Delta, 1); 412 | io->send_block(KEY, length*3); 413 | block DD;io->recv_block(&DD, 1); 414 | 415 | for(int i = 0; i < length*3; ++i) { 416 | block tmp;io->recv_block(&tmp, 1); 417 | if(r[i]) tmp = tmp ^ DD; 418 | if (!cmpBlock(&tmp, &MAC[i], 1)) 419 | cout <recv_data(tmp, 3); 426 | bool res = (logic_xor(tmp[0], r[3*i] )) and (logic_xor(tmp[1], r[3*i+1])); 427 | if(res != logic_xor(tmp[2], r[3*i+2]) ) { 428 | cout <recv_block(&DD, 1); 432 | 433 | for(int i = 0; i < length*3; ++i) { 434 | block tmp;io->recv_block(&tmp, 1); 435 | if(r[i]) tmp = tmp ^ DD; 436 | if (!cmpBlock(&tmp, &MAC[i], 1)) 437 | cout <send_block(&fpre->Delta, 1); 440 | io->send_block(KEY, length*3); 441 | } 442 | io->flush(); 443 | } 444 | 445 | void check2(block & MAC, block & KEY) { 446 | if (party == ALICE) { 447 | io->send_block(&fpre->Delta, 1); 448 | io->send_block(&KEY, 1); 449 | block DD;io->recv_block(&DD, 1); 450 | for(int i = 0; i < 1; ++i) { 451 | block tmp;io->recv_block(&tmp, 1); 452 | if(getLSB(MAC)) tmp = tmp ^ DD; 453 | if (!cmpBlock(&tmp, &MAC, 1)) 454 | cout <recv_block(&DD, 1); 458 | for(int i = 0; i < 1; ++i) { 459 | block tmp;io->recv_block(&tmp, 1); 460 | if(getLSB(MAC)) tmp = tmp ^ DD; 461 | if (!cmpBlock(&tmp, &MAC, 1)) 462 | cout <send_block(&fpre->Delta, 1); 465 | io->send_block(&KEY, 1); 466 | } 467 | io->flush(); 468 | } 469 | 470 | void Hash(block H[4][2], const block & a, const block & b, uint64_t i) { 471 | block A[2], B[2]; 472 | A[0] = a; A[1] = a ^ fpre->Delta; 473 | B[0] = b; B[1] = b ^ fpre->Delta; 474 | A[0] = sigma(A[0]); 475 | A[1] = sigma(A[1]); 476 | B[0] = sigma(sigma(B[0])); 477 | B[1] = sigma(sigma(B[1])); 478 | 479 | H[0][1] = H[0][0] = A[0] ^ B[0]; 480 | H[1][1] = H[1][0] = A[0] ^ B[1]; 481 | H[2][1] = H[2][0] = A[1] ^ B[0]; 482 | H[3][1] = H[3][0] = A[1] ^ B[1]; 483 | for(uint64_t j = 0; j < 4; ++j) { 484 | H[j][0] = H[j][0] ^ makeBlock(4*i+j, 0); 485 | H[j][1] = H[j][1] ^ makeBlock(4*i+j, 1); 486 | } 487 | prp.permute_block((block *)H, 8); 488 | } 489 | 490 | void Hash(block H[2], block a, block b, uint64_t i, uint64_t row) { 491 | a = sigma(a); 492 | b = sigma(sigma(b)); 493 | H[0] = H[1] = a ^ b; 494 | H[0] = H[0] ^ makeBlock(4*i+row, 0); 495 | H[1] = H[1] ^ makeBlock(4*i+row, 1); 496 | prp.permute_block((block *)H, 2); 497 | } 498 | 499 | bool logic_xor(bool a, bool b) { 500 | return a!= b; 501 | } 502 | }; 503 | } 504 | #endif// C2PC_H__ 505 | -------------------------------------------------------------------------------- /emp-ag2pc/amortized_2pc.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AG2PC_AMORTIZED_C2PC_H__ 2 | #define EMP_AG2PC_AMORTIZED_C2PC_H__ 3 | #include 4 | #include 5 | #include "emp-ag2pc/fpre.h" 6 | 7 | //#define __debug 8 | namespace emp { 9 | template 10 | class AmortizedC2PC { public: 11 | const static int SSP = 5;//5*8 in fact... 12 | const block MASK = makeBlock(0x0ULL, 0xFFFFFULL); 13 | Fpre* fpre = nullptr; 14 | block * mac[exec]; 15 | block * key[exec]; 16 | 17 | block * preprocess_mac; 18 | block * preprocess_key; 19 | 20 | block * sigma_mac[exec]; 21 | block * sigma_key[exec]; 22 | 23 | block * labels[exec]; 24 | 25 | bool * mask[exec]; 26 | BristolFormat * cf; 27 | T * io; 28 | int num_ands = 0; 29 | int party, total_pre; 30 | int exec_times = 0; 31 | bool * x1[exec]; 32 | bool * y1[exec]; 33 | bool * x2[exec]; 34 | bool * y2[exec]; 35 | 36 | AmortizedC2PC(T * io, int party, BristolFormat * cf) { 37 | this->party = party; 38 | this->io = io; 39 | this->cf = cf; 40 | for(int i = 0; i < cf->num_gate; ++i) { 41 | if (cf->gates[4*i+3] == AND_GATE) 42 | ++num_ands; 43 | } 44 | total_pre = cf->n1 + cf->n2 + num_ands; 45 | fpre = new Fpre(io, party, num_ands*exec); 46 | 47 | preprocess_mac = new block[total_pre*exec]; 48 | preprocess_key = new block[total_pre*exec]; 49 | 50 | for(int i = 0; i < exec; ++i) { 51 | x1[i] = new bool[num_ands]; 52 | y1[i] = new bool[num_ands]; 53 | x2[i] = new bool[num_ands]; 54 | y2[i] = new bool[num_ands]; 55 | 56 | key[i] = new block[cf->num_wire]; 57 | mac[i] = new block[cf->num_wire]; 58 | 59 | //sigma values in the paper 60 | sigma_mac[i] = new block[num_ands]; 61 | sigma_key[i] = new block[num_ands]; 62 | 63 | labels[i] = new block[cf->num_wire]; 64 | GT[i] = new block[num_ands][4][2]; 65 | GTK[i] = new block[num_ands][4]; 66 | GTM[i] = new block[num_ands][4]; 67 | mask[i] = new bool[cf->n1 + cf->n2]; 68 | } 69 | } 70 | ~AmortizedC2PC() { 71 | for(int i = 0; i < exec; ++i) { 72 | delete[] key[i]; 73 | delete[] mac[i]; 74 | delete[] GT[i]; 75 | delete[] GTK[i]; 76 | delete[] GTM[i]; 77 | 78 | delete[] sigma_mac[i]; 79 | delete[] sigma_key[i]; 80 | 81 | delete[] labels[i]; 82 | delete[] mask[i]; 83 | delete[] x1[i]; 84 | delete[] x2[i]; 85 | delete[] y1[i]; 86 | delete[] y2[i]; 87 | 88 | } 89 | delete[] preprocess_mac; 90 | delete[] preprocess_key; 91 | delete fpre; 92 | } 93 | 94 | PRG prg; 95 | PRP prp; 96 | block (* GT[exec])[4][2]; 97 | block (* GTK[exec])[4]; 98 | block (* GTM[exec])[4]; 99 | 100 | //not allocation 101 | block * ANDS_mac[exec]; 102 | block * ANDS_key[exec]; 103 | void function_independent() { 104 | if(party == ALICE) { 105 | for(int e = 0; e < exec; ++e) 106 | prg.random_block(labels[e], total_pre); 107 | } 108 | 109 | fpre->refill(); 110 | for(int e = 0; e < exec; ++e) { 111 | ANDS_mac[e] = fpre->MAC + 3 * e * num_ands; 112 | ANDS_key[e] = fpre->KEY + 3 * e * num_ands; 113 | } 114 | 115 | if(fpre->party == ALICE) { 116 | fpre->abit1[0]->send_dot(preprocess_key, exec*total_pre); 117 | fpre->io[0]->flush(); 118 | fpre->abit2[0]->recv_dot(preprocess_mac, exec*total_pre); 119 | fpre->io2[0]->flush(); 120 | } else { 121 | fpre->abit1[0]->recv_dot(preprocess_mac, exec*total_pre); 122 | fpre->io[0]->flush(); 123 | fpre->abit2[0]->send_dot(preprocess_key, exec*total_pre); 124 | fpre->io2[0]->flush(); 125 | } 126 | for(int i = 0; i < exec; ++i) { 127 | memcpy(key[i], preprocess_key + total_pre * i, (cf->n1+cf->n2)*sizeof(block)); 128 | memcpy(mac[i], preprocess_mac + total_pre * i, (cf->n1+cf->n2)*sizeof(block)); 129 | } 130 | } 131 | void function_dependent_st() { 132 | int ands = cf->n1+cf->n2; 133 | 134 | for(int i = 0; i < cf->num_gate; ++i) { 135 | if (cf->gates[4*i+3] == AND_GATE) { 136 | for(int e = 0; e < exec; ++e) { 137 | key[e][cf->gates[4*i+2]] = preprocess_key[e*total_pre + ands]; 138 | mac[e][cf->gates[4*i+2]] = preprocess_mac[e*total_pre +ands]; 139 | } 140 | ++ands; 141 | } 142 | } 143 | 144 | for(int e = 0; e < exec; ++e) 145 | for(int i = 0; i < cf->num_gate; ++i) { 146 | if (cf->gates[4*i+3] == XOR_GATE) { 147 | key[e][cf->gates[4*i+2]] = key[e][cf->gates[4*i]] ^ key[e][cf->gates[4*i+1]]; 148 | mac[e][cf->gates[4*i+2]] = mac[e][cf->gates[4*i]] ^ mac[e][cf->gates[4*i+1]]; 149 | if(party == ALICE) 150 | labels[e][cf->gates[4*i+2]] = labels[e][cf->gates[4*i]] ^ labels[e][cf->gates[4*i+1]]; 151 | } else if (cf->gates[4*i+3] == NOT_GATE) { 152 | if(party == ALICE) 153 | labels[e][cf->gates[4*i+2]] = labels[e][cf->gates[4*i]] ^ fpre->Delta; 154 | 155 | key[e][cf->gates[4*i+2]] = key[e][cf->gates[4*i]]; 156 | mac[e][cf->gates[4*i+2]] = mac[e][cf->gates[4*i]]; 157 | } 158 | } 159 | for(int e = 0; e < exec; ++e) { 160 | ands = 0; 161 | for(int i = 0; i < cf->num_gate; ++i) { 162 | if (cf->gates[4*i+3] == AND_GATE) { 163 | x1[e][ands] = getLSB(mac[e][cf->gates[4*i]] ^ ANDS_mac[e][3*ands]); 164 | y1[e][ands] = getLSB(mac[e][cf->gates[4*i+1]] ^ ANDS_mac[e][3*ands+1]); 165 | ands++; 166 | } 167 | } 168 | } 169 | 170 | if(party == ALICE) { 171 | for(int e = 0; e < exec; ++e) { 172 | io->send_bool(x1[e], num_ands); 173 | io->send_bool(y1[e], num_ands); 174 | } 175 | for(int e = 0; e < exec; ++e) { 176 | io->recv_bool(x2[e], num_ands); 177 | io->recv_bool(y2[e], num_ands); 178 | } 179 | } else { 180 | for(int e = 0; e < exec; ++e) { 181 | io->recv_bool(x2[e], num_ands); 182 | io->recv_bool(y2[e], num_ands); 183 | } 184 | for(int e = 0; e < exec; ++e) { 185 | io->send_bool(x1[e], num_ands); 186 | io->send_bool(y1[e], num_ands); 187 | } 188 | } 189 | 190 | for(int e = 0; e < exec; ++e) 191 | for(int i = 0; i < num_ands; ++i) { 192 | x1[e][i] = logic_xor(x1[e][i], x2[e][i]); 193 | y1[e][i] = logic_xor(y1[e][i], y2[e][i]); 194 | } 195 | for(int e = 0; e < exec; ++e) { 196 | ands = 0; 197 | for(int i = 0; i < cf->num_gate; ++i) { 198 | if (cf->gates[4*i+3] == AND_GATE) { 199 | sigma_mac[e][ands] = ANDS_mac[e][3*ands+2]; 200 | sigma_key[e][ands] = ANDS_key[e][3*ands+2]; 201 | if(x1[e][ands]) { 202 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ ANDS_mac[e][3*ands+1]; 203 | sigma_key[e][ands] = sigma_key[e][ands] ^ ANDS_key[e][3*ands+1]; 204 | } 205 | if(y1[e][ands]) { 206 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ ANDS_mac[e][3*ands]; 207 | sigma_key[e][ands] = sigma_key[e][ands] ^ ANDS_key[e][3*ands]; 208 | } 209 | if(x1[e][ands] and y1[e][ands]) { 210 | if(party == ALICE) { 211 | sigma_key[e][ands] = sigma_key[e][ands] ^ fpre->Delta; 212 | sigma_key[e][ands] = sigma_key[e][ands] ^ makeBlock(0,1); 213 | } 214 | else 215 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ makeBlock(0,1); 216 | } 217 | #ifdef __debug 218 | block MM[] = {mac[e][cf->gates[4*i]], mac[e][cf->gates[4*i+1]], sigma_mac[e][ands]}; 219 | block KK[] = {key[e][cf->gates[4*i]], key[e][cf->gates[4*i+1]], sigma_key[e][ands]}; 220 | bool VV[] = {value[e][cf->gates[4*i]], value[e][cf->gates[4*i+1]], sigma_value[e][ands]}; 221 | check(MM, KK, VV); 222 | #endif 223 | ands++; 224 | } 225 | }//sigma_[] stores the and of input wires to each AND gates 226 | } 227 | 228 | 229 | block H[4][2]; 230 | block K[4], M[4]; 231 | for(int e = 0; e < exec; ++e) { 232 | ands = 0; 233 | for(int i = 0; i < cf->num_gate; ++i) { 234 | if(cf->gates[4*i+3] == AND_GATE) { 235 | M[0] = sigma_mac[e][ands] ^ mac[e][cf->gates[4*i+2]]; 236 | M[1] = M[0] ^ mac[e][cf->gates[4*i]]; 237 | M[2] = M[0] ^ mac[e][cf->gates[4*i+1]]; 238 | M[3] = M[1] ^ mac[e][cf->gates[4*i+1]]; 239 | if(party == BOB) 240 | M[3] = M[3] ^ makeBlock(0,1); 241 | 242 | K[0] = sigma_key[e][ands] ^ key[e][cf->gates[4*i+2]]; 243 | K[1] = K[0] ^ key[e][cf->gates[4*i]]; 244 | K[2] = K[0] ^ key[e][cf->gates[4*i+1]]; 245 | K[3] = K[1] ^ key[e][cf->gates[4*i+1]]; 246 | if(party == ALICE) { 247 | K[3] = K[3] ^ fpre->Delta; 248 | K[3] = K[3] ^ makeBlock(0,1); 249 | } 250 | 251 | if(party == ALICE) { 252 | Hash(H, labels[e][cf->gates[4*i]], labels[e][cf->gates[4*i+1]], i); 253 | for(int j = 0; j < 4; ++j) { 254 | H[j][0] = H[j][0] ^ M[j]; 255 | H[j][1] = H[j][1] ^ K[j] ^ labels[e][cf->gates[4*i+2]]; 256 | if(getLSB(M[j])) 257 | H[j][1] = H[j][1] ^ fpre->Delta;; 258 | #ifdef __debug 259 | check2(M[j], K[j], r[j]); 260 | #endif 261 | } 262 | for(int j = 0; j < 4; ++j ) { 263 | send_partial_block(io, &H[j][0], 1); 264 | io->send_block(&H[j][1], 1); 265 | } 266 | 267 | } else { 268 | memcpy(GTK[e][ands], K, sizeof(block)*4); 269 | memcpy(GTM[e][ands], M, sizeof(block)*4); 270 | #ifdef __debug 271 | for(int j = 0; j < 4; ++j) 272 | check2(M[j], K[j], r[j]); 273 | #endif 274 | for(int j = 0; j < 4; ++j ) { 275 | recv_partial_block(io, >[e][ands][j][0], 1); 276 | io->recv_block(>[e][ands][j][1], 1); 277 | } 278 | 279 | } 280 | ++ands; 281 | } 282 | } 283 | } 284 | 285 | block tmp; 286 | if(party == ALICE) { 287 | for(int e = 0; e < exec; ++e) 288 | send_partial_block(io, mac[e], cf->n1); 289 | 290 | for(int e = 0; e < exec; ++e) 291 | for(int i = cf->n1; i < cf->n1+cf->n2; ++i) { 292 | recv_partial_block(io, &tmp, 1); 293 | block ttt = key[e][i] ^ fpre->Delta; 294 | ttt = ttt & MASK; 295 | block mask_key = key[e][i] & MASK; 296 | tmp = tmp & MASK; 297 | 298 | if(cmpBlock(&tmp, &mask_key, 1)) 299 | mask[e][i] = false; 300 | else if(cmpBlock(&tmp, &ttt, 1)) 301 | mask[e][i] = true; 302 | else cout <<"no match! ALICE\t"<n1; ++i) { 307 | recv_partial_block(io, &tmp, 1); 308 | block ttt = key[e][i] ^ fpre->Delta; 309 | ttt = ttt & MASK; 310 | tmp = tmp & MASK; 311 | block mask_key = key[e][i] & MASK; 312 | 313 | if(cmpBlock(&tmp, &mask_key, 1)) { 314 | mask[e][i] = false; 315 | } else if(cmpBlock(&tmp, &ttt, 1)) { 316 | mask[e][i] = true; 317 | } 318 | else cout <<"no match! BOB\t"<(io, mac[e]+cf->n1, cf->n2); 322 | } 323 | } 324 | 325 | void function_dependent() { 326 | int e = 0; 327 | vector> res; 328 | for(int I = 0; I < fpre->THDS and e < exec; ++I, ++e) { 329 | res.push_back(fpre->pool->enqueue( 330 | &AmortizedC2PC::function_dependent_thread, this, e, I 331 | )); 332 | } 333 | while (e < exec) { 334 | for(int I = 0; I < fpre->THDS and e < exec; ++I, ++e) { 335 | res[I].get(); 336 | res[I] = fpre->pool->enqueue( 337 | &AmortizedC2PC::function_dependent_thread, this, e, I); 338 | } 339 | } 340 | for(auto& a : res) 341 | a.get(); 342 | } 343 | void function_dependent_thread(int e, int I) { 344 | int ands = cf->n1+cf->n2; 345 | 346 | for(int i = 0; i < cf->num_gate; ++i) { 347 | if (cf->gates[4*i+3] == AND_GATE) { 348 | key[e][cf->gates[4*i+2]] = preprocess_key[e*total_pre + ands]; 349 | mac[e][cf->gates[4*i+2]] = preprocess_mac[e*total_pre +ands]; 350 | ++ands; 351 | } 352 | } 353 | 354 | for(int i = 0; i < cf->num_gate; ++i) { 355 | if (cf->gates[4*i+3] == XOR_GATE) { 356 | key[e][cf->gates[4*i+2]] = key[e][cf->gates[4*i]] ^ key[e][cf->gates[4*i+1]]; 357 | mac[e][cf->gates[4*i+2]] = mac[e][cf->gates[4*i]] ^ mac[e][cf->gates[4*i+1]]; 358 | if(party == ALICE) 359 | labels[e][cf->gates[4*i+2]] = labels[e][cf->gates[4*i]] ^ labels[e][cf->gates[4*i+1]];; 360 | } else if (cf->gates[4*i+3] == NOT_GATE) { 361 | if(party == ALICE) 362 | labels[e][cf->gates[4*i+2]] = labels[e][cf->gates[4*i]] ^ fpre->Delta; 363 | key[e][cf->gates[4*i+2]] = key[e][cf->gates[4*i]]; 364 | mac[e][cf->gates[4*i+2]] = mac[e][cf->gates[4*i]]; 365 | } 366 | } 367 | ands = 0; 368 | for(int i = 0; i < cf->num_gate; ++i) { 369 | if (cf->gates[4*i+3] == AND_GATE) { 370 | x1[e][ands] = getLSB(mac[e][cf->gates[4*i]] ^ ANDS_mac[e][3*ands]); 371 | y1[e][ands] = getLSB(mac[e][cf->gates[4*i+1]] ^ ANDS_mac[e][3*ands+1]); 372 | ands++; 373 | } 374 | } 375 | 376 | if(party == ALICE) { 377 | fpre->io2[I]->send_bool(x1[e], num_ands); 378 | fpre->io2[I]->send_bool(y1[e], num_ands); 379 | fpre->io2[I]->recv_bool(x2[e], num_ands); 380 | fpre->io2[I]->recv_bool(y2[e], num_ands); 381 | } else { 382 | fpre->io2[I]->recv_bool(x2[e], num_ands); 383 | fpre->io2[I]->recv_bool(y2[e], num_ands); 384 | fpre->io2[I]->send_bool(x1[e], num_ands); 385 | fpre->io2[I]->send_bool(y1[e], num_ands); 386 | } 387 | 388 | for(int i = 0; i < num_ands; ++i) { 389 | x1[e][i] = logic_xor(x1[e][i], x2[e][i]); 390 | y1[e][i] = logic_xor(y1[e][i], y2[e][i]); 391 | } 392 | ands = 0; 393 | for(int i = 0; i < cf->num_gate; ++i) { 394 | if (cf->gates[4*i+3] == AND_GATE) { 395 | sigma_mac[e][ands] = ANDS_mac[e][3*ands+2]; 396 | sigma_key[e][ands] = ANDS_key[e][3*ands+2]; 397 | if(x1[e][ands]) { 398 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ ANDS_mac[e][3*ands+1]; 399 | sigma_key[e][ands] = sigma_key[e][ands] ^ ANDS_key[e][3*ands+1]; 400 | } 401 | if(y1[e][ands]) { 402 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ ANDS_mac[e][3*ands]; 403 | sigma_key[e][ands] = sigma_key[e][ands] ^ ANDS_key[e][3*ands]; 404 | } 405 | if(x1[e][ands] and y1[e][ands]) { 406 | if(party == ALICE) { 407 | sigma_key[e][ands] = sigma_key[e][ands] ^ fpre->Delta; 408 | sigma_key[e][ands] = sigma_key[e][ands] ^ makeBlock(0,1); 409 | 410 | } 411 | else 412 | sigma_mac[e][ands] = sigma_mac[e][ands] ^ makeBlock(0,1); 413 | } 414 | #ifdef __debug 415 | block MM[] = {mac[e][cf->gates[4*i]], mac[e][cf->gates[4*i+1]], sigma_mac[e][ands]}; 416 | block KK[] = {key[e][cf->gates[4*i]], key[e][cf->gates[4*i+1]], sigma_key[e][ands]}; 417 | bool VV[] = {value[e][cf->gates[4*i]], value[e][cf->gates[4*i+1]], sigma_value[e][ands]}; 418 | check(MM, KK, VV); 419 | #endif 420 | ands++; 421 | } 422 | }//sigma_[] stores the and of input wires to each AND gates 423 | 424 | 425 | block H[4][2]; 426 | block K[4], M[4]; 427 | ands = 0; 428 | for(int i = 0; i < cf->num_gate; ++i) { 429 | if(cf->gates[4*i+3] == AND_GATE) { 430 | M[0] = sigma_mac[e][ands] ^ mac[e][cf->gates[4*i+2]]; 431 | M[1] = M[0] ^ mac[e][cf->gates[4*i]]; 432 | M[2] = M[0] ^ mac[e][cf->gates[4*i+1]]; 433 | M[3] = M[1] ^ mac[e][cf->gates[4*i+1]]; 434 | if(party == BOB) 435 | M[3] = M[3] ^ makeBlock(0,1); 436 | 437 | K[0] = sigma_key[e][ands] ^ key[e][cf->gates[4*i+2]]; 438 | K[1] = K[0] ^ key[e][cf->gates[4*i]]; 439 | K[2] = K[0] ^ key[e][cf->gates[4*i+1]]; 440 | K[3] = K[1] ^ key[e][cf->gates[4*i+1]]; 441 | if(party == ALICE) { 442 | K[3] = K[3] ^ fpre->Delta; 443 | K[3] = K[3] ^ makeBlock(0,1); 444 | } 445 | 446 | if(party == ALICE) { 447 | Hash(H, labels[e][cf->gates[4*i]], labels[e][cf->gates[4*i+1]], i); 448 | for(int j = 0; j < 4; ++j) { 449 | H[j][0] = H[j][0] ^ M[j]; 450 | H[j][1] = H[j][1] ^ K[j] ^ labels[e][cf->gates[4*i+2]]; 451 | if(getLSB(M[j])) 452 | H[j][1] = H[j][1] ^ fpre->Delta; 453 | #ifdef __debug 454 | check2(M[j], K[j], r[j]); 455 | #endif 456 | } 457 | for(int j = 0; j < 4; ++j ) { 458 | send_partial_block(fpre->io2[I], &H[j][0], 1); 459 | fpre->io2[I]->send_block(&H[j][1], 1); 460 | } 461 | } else { 462 | memcpy(GTK[e][ands], K, sizeof(block)*4); 463 | memcpy(GTM[e][ands], M, sizeof(block)*4); 464 | #ifdef __debug 465 | for(int j = 0; j < 4; ++j) 466 | check2(M[j], K[j], r[j]); 467 | #endif 468 | for(int j = 0; j < 4; ++j ) { 469 | recv_partial_block(fpre->io2[I], >[e][ands][j][0], 1); 470 | fpre->io2[I]->recv_block(>[e][ands][j][1], 1); 471 | } 472 | } 473 | ++ands; 474 | } 475 | } 476 | 477 | block tmp; 478 | if(party == ALICE) { 479 | send_partial_block(fpre->io2[I], mac[e], cf->n1); 480 | for(int i = cf->n1; i < cf->n1+cf->n2; ++i) { 481 | recv_partial_block(fpre->io2[I], &tmp, 1); 482 | block ttt = key[e][i] ^ fpre->Delta; 483 | ttt = ttt & MASK; 484 | block mask_key = key[e][i] & MASK; 485 | tmp = tmp & MASK; 486 | if(cmpBlock(&tmp, &mask_key, 1)) 487 | mask[e][i] = false; 488 | else if(cmpBlock(&tmp, &ttt, 1)) 489 | mask[e][i] = true; 490 | else cout <<"no match! ALICE\t"<n1; ++i) { 494 | recv_partial_block(fpre->io2[I], &tmp, 1); 495 | block ttt = key[e][i] ^ fpre->Delta; 496 | ttt = ttt & MASK; 497 | tmp = tmp & MASK; 498 | block mask_key = key[e][i] & MASK; 499 | if(cmpBlock(&tmp, &mask_key, 1)) { 500 | mask[e][i] = false; 501 | } else if(cmpBlock(&tmp, &ttt, 1)) { 502 | mask[e][i] = true; 503 | } 504 | else cout <<"no match! BOB\t"<(fpre->io2[I], mac[e]+cf->n1, cf->n2); 507 | } 508 | fpre->io2[I]->flush(); 509 | } 510 | 511 | 512 | void online (const bool * input, bool * output) { 513 | uint8_t * mask_input = new uint8_t[cf->num_wire]; 514 | memset(mask_input, 0, cf->num_wire); 515 | block tmp; 516 | #ifdef __debug 517 | for(int e = 0; e < exec; ++e) 518 | for(int i = 0; i < cf->n1+cf->n2; ++i) 519 | check2(mac[e][i], key[e][i], value[e][i]); 520 | #endif 521 | if(party == ALICE) { 522 | for(int i = cf->n1; i < cf->n1+cf->n2; ++i) { 523 | mask_input[i] = logic_xor(input[i], getLSB(mac[exec_times][i])); 524 | mask_input[i] = logic_xor(mask_input[i], mask[exec_times][i]); 525 | } 526 | io->recv_data(mask_input, cf->n1); 527 | io->send_data(mask_input+cf->n1, cf->n2); 528 | for(int i = 0; i < cf->n1 + cf->n2; ++i) { 529 | tmp = labels[exec_times][i]; 530 | if(mask_input[i]) tmp = tmp ^ fpre->Delta; 531 | io->send_block(&tmp, 1); 532 | } 533 | //send output mask data 534 | send_partial_block(io, mac[exec_times]+cf->num_wire - cf->n3, cf->n3); 535 | } else { 536 | for(int i = 0; i < cf->n1; ++i) { 537 | mask_input[i] = logic_xor(input[i], getLSB(mac[exec_times][i])); 538 | mask_input[i] = logic_xor(mask_input[i], mask[exec_times][i]); 539 | } 540 | io->send_data(mask_input, cf->n1); 541 | io->recv_data(mask_input+cf->n1, cf->n2); 542 | io->recv_block(labels[exec_times], cf->n1 + cf->n2); 543 | } 544 | int ands = 0; 545 | if(party == BOB) { 546 | for(int i = 0; i < cf->num_gate; ++i) { 547 | if (cf->gates[4*i+3] == XOR_GATE) { 548 | labels[exec_times][cf->gates[4*i+2]] = labels[exec_times][cf->gates[4*i]] ^ labels[exec_times][cf->gates[4*i+1]]; 549 | mask_input[cf->gates[4*i+2]] = logic_xor(mask_input[cf->gates[4*i]], mask_input[cf->gates[4*i+1]]); 550 | } else if (cf->gates[4*i+3] == AND_GATE) { 551 | int index = 2*mask_input[cf->gates[4*i]] + mask_input[cf->gates[4*i+1]]; 552 | block H[2]; 553 | Hash(H, labels[exec_times][cf->gates[4*i]], labels[exec_times][cf->gates[4*i+1]], i, index); 554 | GT[exec_times][ands][index][0] = GT[exec_times][ands][index][0] ^ H[0]; 555 | GT[exec_times][ands][index][1] = GT[exec_times][ands][index][1] ^ H[1]; 556 | 557 | block ttt = GTK[exec_times][ands][index] ^ fpre->Delta; 558 | ttt = ttt & MASK; 559 | GTK[exec_times][ands][index] = GTK[exec_times][ands][index] & MASK; 560 | GT[exec_times][ands][index][0] = GT[exec_times][ands][index][0] & MASK; 561 | 562 | if(cmpBlock(>[exec_times][ands][index][0], >K[exec_times][ands][index], 1)) 563 | mask_input[cf->gates[4*i+2]] = false; 564 | else if(cmpBlock(>[exec_times][ands][index][0], &ttt, 1)) 565 | mask_input[cf->gates[4*i+2]] = true; 566 | else cout <gates[4*i+2]] = logic_xor(mask_input[cf->gates[4*i+2]], getLSB(GTM[exec_times][ands][index])); 568 | 569 | labels[exec_times][cf->gates[4*i+2]] = GT[exec_times][ands][index][1] ^ GTM[exec_times][ands][index]; 570 | ands++; 571 | } else { 572 | mask_input[cf->gates[4*i+2]] = not mask_input[cf->gates[4*i]]; 573 | labels[exec_times][cf->gates[4*i+2]] = labels[exec_times][cf->gates[4*i]]; 574 | } 575 | } 576 | } 577 | if (party == BOB) { 578 | bool * o = new bool[cf->n3]; 579 | for(int i = 0; i < cf->n3; ++i) { 580 | block tmp; 581 | recv_partial_block(io, &tmp, 1); 582 | tmp = tmp & MASK; 583 | 584 | block ttt = key[exec_times][cf->num_wire - cf-> n3 + i] ^ fpre->Delta; 585 | ttt = ttt & MASK; 586 | key[exec_times][cf->num_wire - cf-> n3 + i] = key[exec_times][cf->num_wire - cf-> n3 + i] & MASK; 587 | 588 | if(cmpBlock(&tmp, &key[exec_times][cf->num_wire - cf-> n3 + i], 1)) 589 | o[i] = false; 590 | else if(cmpBlock(&tmp, &ttt, 1)) 591 | o[i] = true; 592 | else cout <<"no match output label!"<n3; ++i) { 595 | output[i] = logic_xor(o[i], mask_input[cf->num_wire - cf->n3 + i]); 596 | output[i] = logic_xor(output[i], getLSB(mac[exec_times][cf->num_wire - cf->n3 + i])); 597 | } 598 | delete[] o; 599 | } 600 | exec_times++; 601 | delete[] mask_input; 602 | } 603 | 604 | void Hash(block H[4][2], const block & a, const block & b, uint64_t i) { 605 | block A[2], B[2]; 606 | A[0] = a; A[1] = a ^ fpre->Delta; 607 | B[0] = b; B[1] = b ^ fpre->Delta; 608 | A[0] = sigma(A[0]); 609 | A[1] = sigma(A[1]); 610 | B[0] = sigma(sigma(B[0])); 611 | B[1] = sigma(sigma(B[1])); 612 | 613 | H[0][1] = H[0][0] = A[0] ^ B[0]; 614 | H[1][1] = H[1][0] = A[0] ^ B[1]; 615 | H[2][1] = H[2][0] = A[1] ^ B[0]; 616 | H[3][1] = H[3][0] = A[1] ^ B[1]; 617 | for(uint64_t j = 0; j < 4; ++j) { 618 | H[j][0] = H[j][0] ^ _mm_set_epi64x(4*i+j, 0ULL); 619 | H[j][1] = H[j][1] ^ _mm_set_epi64x(4*i+j, 1ULL); 620 | } 621 | prp.permute_block((block *)H, 8); 622 | } 623 | 624 | void Hash(block H[2], block a, block b, uint64_t i, uint64_t row) { 625 | a = sigma(a); 626 | b = sigma(sigma(b)); 627 | H[0] = H[1] = a ^ b; 628 | H[0] = H[0] ^ _mm_set_epi64x(4*i+row, 0ULL); 629 | H[1] = H[1] ^ _mm_set_epi64x(4*i+row, 1ULL);; 630 | prp.permute_block((block *)H, 2); 631 | } 632 | 633 | 634 | bool logic_xor(bool a, bool b) { 635 | return a!= b; 636 | if(a) if(not b) return true; 637 | if(not a) if(b) return true; 638 | return false; 639 | } 640 | string tostring(bool a) { 641 | if(a) return "T"; 642 | else return "F"; 643 | } 644 | }; 645 | } 646 | #endif// AMORTIZED_C2PC_H__ 647 | --------------------------------------------------------------------------------