├── .github └── workflows │ ├── arm.yml │ └── x86.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── emp-agmpc-config.cmake ├── debug ├── emp-agmpc ├── abitmp.h ├── cmpc_config.h ├── emp-agmpc.h ├── flexible_input_output.h ├── fpremp.h ├── helper.h ├── mpc.h └── netmp.h ├── lgtm.yml ├── run └── test ├── CMakeLists.txt ├── aes.cpp ├── ands.txt ├── not.txt ├── pr10_circuit.txt ├── pr10_test.cpp ├── scratch.cpp ├── sha1.cpp ├── sha256.cpp ├── test.h ├── test_in_out.cpp ├── test_mpc.cpp ├── test_mpc_individual.cpp ├── triple.cpp └── xor.txt /.github/workflows/arm.yml: -------------------------------------------------------------------------------- 1 | name: arm 2 | on: [push] 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 | env: 12 | BUILD_TYPE: ${{matrix.build_type}} 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: install dependency 16 | run: | 17 | wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py 18 | python3 install.py --deps --tool --ot 19 | - name: Create Build Environment 20 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_RANDOM_DEVICE=On && make 21 | - name: Test 22 | shell: bash 23 | run: make test 24 | -------------------------------------------------------------------------------- /.github/workflows/x86.yml: -------------------------------------------------------------------------------- 1 | name: x86 2 | on: [push] 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 | env: 12 | BUILD_TYPE: ${{matrix.build_type}} 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: install dependency 16 | run: | 17 | wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py 18 | python install.py --deps --tool --ot 19 | - name: Create Build Environment 20 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DUSE_RANDOM_DEVICE=On && make 21 | - name: Test 22 | shell: bash 23 | run: make test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Testing/ 2 | *CTestTestfile.cmake 3 | CMakeCache.txt 4 | CMakeFiles/ 5 | Makefile 6 | bin/ 7 | cmake_install.cmake 8 | *.DS_Store 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | 27 | # Compiled Static libraries 28 | *.lai 29 | *.la 30 | *.a 31 | *.lib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | perf.data* 39 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.11) 2 | project (emp-agmpc) 3 | set(NAME "emp-agmpc") 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 | install(FILES cmake/emp-agmpc-config.cmake DESTINATION cmake/) 12 | install(DIRECTORY emp-agmpc DESTINATION include/) 13 | 14 | ENABLE_TESTING() 15 | ADD_SUBDIRECTORY(test) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xiao Wang (wangxiao@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Enquiries about further applications and development opportunities are welcome. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EMP-agmpc 2 | ![arm](https://github.com/emp-toolkit/emp-agmpc/workflows/arm/badge.svg) 3 | ![x86](https://github.com/emp-toolkit/emp-agmpc/workflows/x86/badge.svg) 4 | [![Total alerts](https://img.shields.io/lgtm/alerts/g/emp-toolkit/emp-agmpc.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/emp-toolkit/emp-agmpc/alerts/) 5 | [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/emp-toolkit/emp-agmpc.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/emp-toolkit/emp-agmpc/context:cpp) 6 | 7 | 8 | 9 | ## Global-Scale Secure Multiparty Computation 10 | 11 | More details of the protocol can be found in the [paper](https://eprint.iacr.org/2017/189). 12 | 13 | 14 | 15 | 16 | # Installation 17 | 1. `wget https://raw.githubusercontent.com/emp-toolkit/emp-readme/master/scripts/install.py` 18 | 2. `python[3] install.py --deps --tool --ot --agmpc` 19 | 1. By default it will build for Release. `-DCMAKE_BUILD_TYPE=[Release|Debug]` option is also available. 20 | 2. No sudo? Change [`CMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/v2.8.8/cmake.html#variable%3aCMAKE_INSTALL_PREFIX). 21 | 22 | 23 | ### Question 24 | Please send email to wangxiao1254@gmail.com 25 | 26 | -------------------------------------------------------------------------------- /cmake/emp-agmpc-config.cmake: -------------------------------------------------------------------------------- 1 | find_package(emp-tool) 2 | find_package(emp-ot) 3 | find_path(EMP-AGMPC_INCLUDE_DIR emp-agmpc/emp-agmpc.h) 4 | 5 | include(FindPackageHandleStandardArgs) 6 | 7 | find_package_handle_standard_args(EMP-AGMPC DEFAULT_MSG EMP-AGMPC_INCLUDE_DIR) 8 | 9 | if(EMP-AGMPC_FOUND) 10 | set(EMP-AGMPC_INCLUDE_DIRS ${EMP-AGMPC_INCLUDE_DIR} ${EMP-OT_INCLUDE_DIRS}) 11 | set(EMP-AGMPC_LIBRARIES ${EMP-OT_LIBRARIES}) 12 | endif() -------------------------------------------------------------------------------- /debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | $1 1 12345 & $1 2 12345 & valgrind --leak-check=full $1 3 12345 3 | #valgrind --leak-check=full $1 1 12345 & $1 2 12345 & $1 3 12345 4 | #$1 1 12345 & $1 2 12345 & perf record $1 3 12345 5 | #perf record -g $1 1 12345 & $1 2 12345 & $1 3 12345 6 | #valgrind --leak-check=full $1 1 12345 & $1 2 12345 & $1 3 12345 -------------------------------------------------------------------------------- /emp-agmpc/abitmp.h: -------------------------------------------------------------------------------- 1 | #ifndef ABIT_MP_H__ 2 | #define ABIT_MP_H__ 3 | #include 4 | #include 5 | #include "netmp.h" 6 | #include "helper.h" 7 | 8 | template 9 | class ABitMP { public: 10 | IKNP *abit1[nP+1]; 11 | IKNP *abit2[nP+1]; 12 | NetIOMP *io; 13 | ThreadPool * pool; 14 | int party; 15 | PRG prg; 16 | block Delta; 17 | Hash hash; 18 | int ssp; 19 | block * pretable; 20 | ABitMP(NetIOMP* io, ThreadPool * pool, int party, bool * _tmp = nullptr, int ssp = 40) { 21 | this->ssp = ssp; 22 | this->io = io; 23 | this->pool = pool; 24 | this->party = party; 25 | bool tmp[128]; 26 | if(_tmp == nullptr) { 27 | prg.random_bool(tmp, 128); 28 | } else { 29 | memcpy(tmp, _tmp, 128); 30 | } 31 | 32 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if(i < j) { 33 | if(i == party) { 34 | abit1[j] = new IKNP(io->get(j, false)); 35 | abit2[j] = new IKNP(io->get(j, true)); 36 | } else if (j == party) { 37 | abit2[i] = new IKNP(io->get(i, false)); 38 | abit1[i] = new IKNP(io->get(i, true)); 39 | } 40 | } 41 | 42 | vector> res;//relic multi-thread problems... 43 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if(i < j) { 44 | if(i == party) { 45 | res.push_back(pool->enqueue([this, io, tmp, j]() { 46 | abit1[j]->setup_send(tmp); 47 | io->flush(j); 48 | })); 49 | res.push_back(pool->enqueue([this, io, j]() { 50 | abit2[j]->setup_recv(); 51 | io->flush(j); 52 | })); 53 | } else if (j == party) { 54 | res.push_back(pool->enqueue([this, io, i]() { 55 | abit2[i]->setup_recv(); 56 | io->flush(i); 57 | })); 58 | res.push_back(pool->enqueue([this, io, tmp, i]() { 59 | abit1[i]->setup_send(tmp); 60 | io->flush(i); 61 | })); 62 | } 63 | } 64 | joinNclean(res); 65 | 66 | if(party == 1) 67 | Delta = abit1[2]->Delta; 68 | else 69 | Delta = abit1[1]->Delta; 70 | } 71 | ~ABitMP() { 72 | for(int i = 1; i <= nP; ++i) if( i!= party ) { 73 | delete abit1[i]; 74 | delete abit2[i]; 75 | } 76 | } 77 | void compute(block * MAC[nP+1], block * KEY[nP+1], bool* data, int length) { 78 | vector> res; 79 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 80 | int party2 = i + j - party; 81 | res.push_back(pool->enqueue([this, KEY, length, party2]() { 82 | abit1[party2]->send_cot(KEY[party2], length); 83 | io->flush(party2); 84 | })); 85 | res.push_back(pool->enqueue([this, MAC, data, length, party2]() { 86 | abit2[party2]->recv_cot(MAC[party2], data, length); 87 | io->flush(party2); 88 | })); 89 | } 90 | joinNclean(res); 91 | #ifdef __debug 92 | check_MAC(io, MAC, KEY, data, Delta, length, party); 93 | #endif 94 | } 95 | 96 | future check(block * MAC[nP+1], block * KEY[nP+1], bool* data, int length) { 97 | future ret = pool->enqueue([this, MAC, KEY, data, length](){ 98 | check1(MAC, KEY, data, length); 99 | check2(MAC, KEY, data, length); 100 | }); 101 | return ret; 102 | } 103 | 104 | void check1(block * MAC[nP+1], block * KEY[nP+1], bool* data, int length) { 105 | block seed = sampleRandom(io, &prg, pool, party); 106 | PRG prg2(&seed); 107 | uint8_t * tmp; 108 | block * Ms[nP+1]; 109 | bool * bs[nP+1]; 110 | block * Ks[nP+1]; 111 | block * tMs[nP+1]; 112 | bool * tbs[nP+1]; 113 | 114 | tmp = new uint8_t[ssp*length]; 115 | prg2.random_data(tmp, ssp*length); 116 | for(int i = 0; i < ssp*length; ++i) 117 | tmp[i] = tmp[i] % 4; 118 | // for(int j = 0; j < ssp; ++j) { 119 | // tmp[j] = new bool[length]; 120 | // for(int k = 0; k < ssp; ++k) 121 | // tmp[j][length - ssp + k] = (k == j); 122 | // } 123 | for(int i = 1; i <= nP; ++i) { 124 | Ms[i] = new block[ssp]; 125 | Ks[i] = new block[ssp]; 126 | bs[i] = new bool[ssp]; 127 | memset(Ms[i], 0, ssp*sizeof(block)); 128 | memset(Ks[i], 0, ssp*sizeof(block)); 129 | memset(bs[i], false, ssp); 130 | tMs[i] = new block[ssp]; 131 | tbs[i] = new bool[ssp]; 132 | } 133 | 134 | const int chk = 1; 135 | const int SIZE = 1024*2; 136 | block (* tMAC)[4] = new block[SIZE/chk][4]; 137 | block (* tKEY)[4] = new block[SIZE/chk][4]; 138 | bool (* tb)[4] = new bool[length/chk][4]; 139 | memset(tMAC, 0, sizeof(block)*4*SIZE/chk); 140 | memset(tKEY, 0, sizeof(block)*4*SIZE/chk); 141 | memset(tb, false, 4*length/chk); 142 | for(int i = 0; i < length; i+=chk) { 143 | tb[i/chk][1] = data[i]; 144 | tb[i/chk][2] = data[i+1]; 145 | tb[i/chk][3] = data[i] != data[i+1]; 146 | } 147 | 148 | for(int k = 1; k <= nP; ++k) if(k != party) { 149 | uint8_t * tmpptr = tmp; 150 | for(int tt = 0; tt < length/SIZE; tt++) { 151 | int start = SIZE*tt; 152 | for(int i = SIZE*tt; i < SIZE*(tt+1) and i < length; i+=chk) { 153 | tMAC[(i-start)/chk][1] = MAC[k][i]; 154 | tMAC[(i-start)/chk][2] = MAC[k][i+1]; 155 | tMAC[(i-start)/chk][3] = MAC[k][i] ^ MAC[k][i+1]; 156 | 157 | tKEY[(i-start)/chk][1] = KEY[k][i]; 158 | tKEY[(i-start)/chk][2] = KEY[k][i+1]; 159 | tKEY[(i-start)/chk][3] = KEY[k][i] ^ KEY[k][i+1]; 160 | for(int j = 0; j < ssp; ++j) { 161 | Ms[k][j] = Ms[k][j] ^ tMAC[(i-start)/chk][*tmpptr]; 162 | Ks[k][j] = Ks[k][j] ^ tKEY[(i-start)/chk][*tmpptr]; 163 | bs[k][j] = bs[k][j] != tb[i/chk][*tmpptr]; 164 | ++tmpptr; 165 | } 166 | } 167 | } 168 | } 169 | delete[] tmp; 170 | vector> res; 171 | //TODO: they should not need to send MACs. 172 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 173 | int party2 = i + j - party; 174 | res.push_back(pool->enqueue([this, Ms, bs, party2]()->bool { 175 | io->send_data(party2, Ms[party2], sizeof(block)*ssp); 176 | io->send_data(party2, bs[party2], ssp); 177 | io->flush(party2); 178 | return false; 179 | })); 180 | res.push_back(pool->enqueue([this, tMs, tbs, Ks, party2]()->bool { 181 | io->recv_data(party2, tMs[party2], sizeof(block)*ssp); 182 | io->recv_data(party2, tbs[party2], ssp); 183 | for(int k = 0; k < ssp; ++k) { 184 | if(tbs[party2][k]) 185 | Ks[party2][k] = Ks[party2][k] ^ Delta; 186 | } 187 | return !cmpBlock(Ks[party2], tMs[party2], ssp); 188 | })); 189 | } 190 | if(joinNcleanCheat(res)) error("cheat check1\n"); 191 | 192 | for(int i = 1; i <= nP; ++i) { 193 | delete[] Ms[i]; 194 | delete[] Ks[i]; 195 | delete[] bs[i]; 196 | delete[] tMs[i]; 197 | delete[] tbs[i]; 198 | } 199 | } 200 | 201 | void check2(block * MAC[nP+1], block * KEY[nP+1], bool* data, int length) { 202 | //last 2*ssp are garbage already. 203 | block * Ks[2], *Ms[nP+1][nP+1]; 204 | block * KK[nP+1]; 205 | bool * bs[nP+1]; 206 | Ks[0] = new block[ssp]; 207 | Ks[1] = new block[ssp]; 208 | for(int i = 1; i <= nP; ++i) { 209 | bs[i] = new bool[ssp]; 210 | KK[i] = new block[ssp]; 211 | for(int j = 1; j <= nP; ++j) 212 | Ms[i][j] = new block[ssp]; 213 | } 214 | char (*dgst)[Hash::DIGEST_SIZE] = new char[nP+1][Hash::DIGEST_SIZE]; 215 | char (*dgst0)[Hash::DIGEST_SIZE] = new char[ssp*(nP+1)][Hash::DIGEST_SIZE]; 216 | char (*dgst1)[Hash::DIGEST_SIZE] = new char[ssp*(nP+1)][Hash::DIGEST_SIZE]; 217 | 218 | 219 | for(int i = 0; i < ssp; ++i) { 220 | Ks[0][i] = zero_block; 221 | for(int j = 1; j <= nP; ++j) if(j != party) 222 | Ks[0][i] = Ks[0][i] ^ KEY[j][length-3*ssp+i]; 223 | 224 | Ks[1][i] = Ks[0][i] ^ Delta; 225 | Hash::hash_once(dgst0[party*ssp+i], &Ks[0][i], sizeof(block)); 226 | Hash::hash_once(dgst1[party*ssp+i], &Ks[1][i], sizeof(block)); 227 | } 228 | Hash h; 229 | h.put(data+length-3*ssp, ssp); 230 | for(int j = 1; j <= nP; ++j) if(j != party) { 231 | h.put(&MAC[j][length-3*ssp], ssp*sizeof(block)); 232 | } 233 | h.digest(dgst[party]); 234 | 235 | vector> res; 236 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 237 | int party2 = i + j - party; 238 | res.push_back(pool->enqueue([this, dgst, dgst0, dgst1, party2](){ 239 | io->send_data(party2, dgst[party], Hash::DIGEST_SIZE); 240 | io->send_data(party2, dgst0[party*ssp], Hash::DIGEST_SIZE*ssp); 241 | io->send_data(party2, dgst1[party*ssp], Hash::DIGEST_SIZE*ssp); 242 | io->recv_data(party2, dgst[party2], Hash::DIGEST_SIZE); 243 | io->recv_data(party2, dgst0[party2*ssp], Hash::DIGEST_SIZE*ssp); 244 | io->recv_data(party2, dgst1[party2*ssp], Hash::DIGEST_SIZE*ssp); 245 | })); 246 | } 247 | joinNclean(res); 248 | 249 | vector> res2; 250 | for(int k = 1; k <= nP; ++k) if(k!= party) 251 | memcpy(Ms[party][k], MAC[k]+length-3*ssp, sizeof(block)*ssp); 252 | 253 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 254 | int party2 = i + j - party; 255 | res2.push_back(pool->enqueue([this, data, MAC, length, party2]() -> bool { 256 | io->send_data(party2, data + length - 3*ssp, ssp); 257 | for(int k = 1; k <= nP; ++k) if(k != party) 258 | io->send_data(party2, MAC[k] + length - 3*ssp, sizeof(block)*ssp); 259 | return false; 260 | })); 261 | res2.push_back(pool->enqueue([this, dgst, bs, Ms, party2]() -> bool { 262 | Hash h; 263 | io->recv_data(party2, bs[party2], ssp); 264 | h.put(bs[party2], ssp); 265 | for(int k = 1; k <= nP; ++k) if(k != party2) { 266 | io->recv_data(party2, Ms[party2][k], sizeof(block)*ssp); 267 | h.put(Ms[party2][k], sizeof(block)*ssp); 268 | } 269 | char tmp[Hash::DIGEST_SIZE];h.digest(tmp); 270 | return strncmp(tmp, dgst[party2], Hash::DIGEST_SIZE) != 0; 271 | })); 272 | } 273 | if(joinNcleanCheat(res2)) error("commitment 1\n"); 274 | 275 | memset(bs[party], false, ssp); 276 | for(int i = 1; i <= nP; ++i) if(i != party) { 277 | for(int j = 0; j < ssp; ++j) 278 | bs[party][j] = bs[party][j] != bs[i][j]; 279 | } 280 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 281 | int party2 = i + j - party; 282 | res2.push_back(pool->enqueue([this, bs, Ks, party2]() -> bool { 283 | io->send_data(party2, bs[party], ssp); 284 | for(int i = 0; i < ssp; ++i) { 285 | if(bs[party][i]) 286 | io->send_data(party2, &Ks[1][i], sizeof(block)); 287 | else 288 | io->send_data(party2, &Ks[0][i], sizeof(block)); 289 | } 290 | io->flush(party2); 291 | return false; 292 | })); 293 | res2.push_back(pool->enqueue([this, KK, dgst0, dgst1, party2]() -> bool { 294 | bool cheat = false; 295 | bool *tmp_bool = new bool[ssp]; 296 | io->recv_data(party2, tmp_bool, ssp); 297 | io->recv_data(party2, KK[party2], ssp*sizeof(block)); 298 | for(int i = 0; i < ssp; ++i) { 299 | char tmp[Hash::DIGEST_SIZE]; 300 | Hash::hash_once(tmp, &KK[party2][i], sizeof(block)); 301 | if(tmp_bool[i]) 302 | cheat = cheat or (strncmp(tmp, dgst1[party2*ssp+i], Hash::DIGEST_SIZE)!=0); 303 | else 304 | cheat = cheat or (strncmp(tmp, dgst0[party2*ssp+i], Hash::DIGEST_SIZE)!=0); 305 | } 306 | delete[] tmp_bool; 307 | return cheat; 308 | })); 309 | } 310 | if(joinNcleanCheat(res2)) error("commitments 2\n"); 311 | 312 | bool cheat = false; 313 | block *tmp_block = new block[ssp]; 314 | for(int i = 1; i <= nP; ++i) if (i != party) { 315 | memset(tmp_block, 0, sizeof(block)*ssp); 316 | for(int j = 1; j <= nP; ++j) if(j != i) { 317 | for(int k = 0; k < ssp; ++k) 318 | tmp_block[k] = tmp_block[k] ^ Ms[j][i][k]; 319 | } 320 | cheat = cheat or !cmpBlock(tmp_block, KK[i], ssp); 321 | } 322 | if(cheat) error("cheat aShare\n"); 323 | 324 | delete[] Ks[0]; 325 | delete[] Ks[1]; 326 | delete[] dgst; 327 | delete[] dgst0; 328 | delete[] dgst1; 329 | delete[] tmp_block; 330 | for(int i = 1; i <= nP; ++i) { 331 | delete[] bs[i]; 332 | delete[] KK[i]; 333 | for(int j = 1; j <= nP; ++j) 334 | delete[] Ms[i][j]; 335 | } 336 | } 337 | }; 338 | #endif //ABIT_MP_H__ 339 | -------------------------------------------------------------------------------- /emp-agmpc/cmpc_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CMPC_CONFIG 2 | #define __CMPC_CONFIG 3 | const static int abit_block_size = 1024; 4 | const static int fpre_threads = 1; 5 | #define LOCALHOST 6 | 7 | #ifdef __clang__ 8 | #define __MORE_FLUSH 9 | #endif 10 | 11 | //#define __debug 12 | const static char *IP[] = {"" 13 | , "127.0.0.1" 14 | , "127.0.0.1" 15 | , "127.0.0.1"}; 16 | 17 | const static bool lan_network = false; 18 | #endif// __C2PC_CONFIG 19 | -------------------------------------------------------------------------------- /emp-agmpc/emp-agmpc.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AGMPC_H__ 2 | #define EMP_AGMPC_H__ 3 | #include "emp-agmpc/abitmp.h" 4 | #include "emp-agmpc/cmpc_config.h" 5 | #include "emp-agmpc/fpremp.h" 6 | #include "emp-agmpc/helper.h" 7 | #include "emp-agmpc/mpc.h" 8 | #include "emp-agmpc/netmp.h" 9 | #endif// EMP_AGMPC_H__ 10 | -------------------------------------------------------------------------------- /emp-agmpc/flexible_input_output.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AGMPC_FLEXIBLE_INPUT_OUTPUT_H 2 | #define EMP_AGMPC_FLEXIBLE_INPUT_OUTPUT_H 3 | 4 | using namespace std; 5 | 6 | template 7 | struct AuthBitShare 8 | { 9 | bool bit_share; 10 | block key[nP + 1]; 11 | block mac[nP + 1]; 12 | }; 13 | 14 | struct BitWithMac 15 | { 16 | bool bit_share; 17 | block mac; 18 | }; 19 | 20 | template 21 | class FlexIn 22 | { 23 | public: 24 | 25 | int len{}; 26 | int party{}; 27 | 28 | bool cmpc_associated = false; 29 | ThreadPool* pool; 30 | bool *value; 31 | block *key[nP + 1]; 32 | block *mac[nP + 1]; 33 | NetIOMP * io; 34 | block Delta; 35 | 36 | vector party_assignment; 37 | // -2 represents an un-authenticated share (e.g., for random tape), 38 | // -1 represents an authenticated share, 39 | // 0 represents public input/output, 40 | 41 | vector plaintext_assignment; // if `party` provides the value for this bit, the plaintext value is here 42 | vector> authenticated_share_assignment; // if this bit is from authenticated shares, the authenticated share is stored here 43 | 44 | FlexIn(int len, int party) { 45 | this->len = len; 46 | this->party = party; 47 | this->pool = pool; 48 | 49 | AuthBitShare empty_abit; 50 | memset(&empty_abit, 0, sizeof(AuthBitShare)); 51 | 52 | party_assignment.resize(len, 0); 53 | plaintext_assignment.resize(len, false); 54 | authenticated_share_assignment.resize(len, empty_abit); 55 | } 56 | 57 | ~FlexIn() { 58 | party_assignment.clear(); 59 | plaintext_assignment.clear(); 60 | authenticated_share_assignment.clear(); 61 | } 62 | 63 | void associate_cmpc(ThreadPool *associated_pool, bool *associated_value, block *associated_mac[nP + 1], block *associated_key[nP + 1], NetIOMP *associated_io, block associated_Delta) { 64 | this->cmpc_associated = true; 65 | this->pool = associated_pool; 66 | this->value = associated_value; 67 | for(int j = 1; j <= nP; j++) { 68 | this->mac[j] = associated_mac[j]; 69 | this->key[j] = associated_key[j]; 70 | } 71 | this->io = associated_io; 72 | this->Delta = associated_Delta; 73 | } 74 | 75 | void assign_party(int pos, int which_party) { 76 | party_assignment[pos] = which_party; 77 | } 78 | 79 | void assign_plaintext_bit(int pos, bool cur_bit) { 80 | assert(party_assignment[pos] == party || party_assignment[pos] == -2 || party_assignment[pos] == 0); 81 | plaintext_assignment[pos] = cur_bit; 82 | } 83 | 84 | void assign_authenticated_bitshare(int pos, AuthBitShare *abit) { 85 | assert(party_assignment[pos] == -1); 86 | memcpy(&authenticated_share_assignment[pos], abit, sizeof(AuthBitShare)); 87 | } 88 | 89 | void input(bool *masked_input_ret) { 90 | assert(cmpc_associated); 91 | 92 | /* assemble an array of the input masks, their macs, and their keys */ 93 | /* 94 | * Then, 95 | * for a plaintext bit, the input mask, as well as its MAC, is sent to the input party, who uses the KEY for verification; 96 | * for an un-authenticated bit, the input mask XOR with the input share is broadcast; 97 | * for an authenticated bit share, they are used to masked the previously data (and then checking its opening) 98 | */ 99 | vector> input_mask; 100 | for(int i = 0; i < len; i++) { 101 | AuthBitShare abit; 102 | abit.bit_share = value[i]; 103 | for(int j = 1; j <= nP; j++) { 104 | if(j != party) { 105 | abit.key[j] = key[j][i]; 106 | abit.mac[j] = mac[j][i]; 107 | } 108 | } 109 | input_mask.emplace_back(abit); 110 | } 111 | 112 | /* 113 | * first of all, handle the case party_assignment[] > 0 114 | */ 115 | 116 | /* prepare the bit shares to open for the corresponding party */ 117 | vector> open_bit_shares_for_plaintext_input_send; 118 | open_bit_shares_for_plaintext_input_send.resize(nP + 1); 119 | 120 | for(int j = 1; j <= nP; j++) { 121 | if(j != party) { 122 | for(int i = 0; i < len; i++) { 123 | BitWithMac mbit{}; 124 | if(party_assignment[i] == j) { 125 | mbit.bit_share = input_mask[i].bit_share; 126 | mbit.mac = input_mask[i].mac[j]; 127 | } 128 | open_bit_shares_for_plaintext_input_send[j].push_back(mbit); 129 | } 130 | } 131 | } 132 | 133 | vector> open_bit_shares_for_plaintext_input_recv; 134 | open_bit_shares_for_plaintext_input_recv.resize(nP + 1); 135 | for(int j = 1; j <= nP; j++) { 136 | open_bit_shares_for_plaintext_input_recv[j].resize(len); 137 | } 138 | 139 | /* 140 | * exchange the opening of the input mask 141 | */ 142 | vector> res; 143 | for (int i = 1; i <= nP; ++i) { 144 | for (int j = 1; j <= nP; ++j) { 145 | if ((i < j) and (i == party or j == party)) { 146 | int party2 = i + j - party; 147 | 148 | res.push_back(pool->enqueue([this, &open_bit_shares_for_plaintext_input_recv, party2]() { 149 | io->recv_data(party2, open_bit_shares_for_plaintext_input_recv[party2].data(), sizeof(BitWithMac) * len); 150 | io->flush(party2); 151 | })); 152 | res.push_back(pool->enqueue([this, &open_bit_shares_for_plaintext_input_send, party2]() { 153 | io->send_data(party2, open_bit_shares_for_plaintext_input_send[party2].data(), sizeof(BitWithMac) * len); 154 | io->flush(party2); 155 | })); 156 | } 157 | } 158 | } 159 | joinNclean(res); 160 | 161 | /* 162 | * verify the input mask 163 | */ 164 | vector> res_check; 165 | for (int j = 1; j <= nP; ++j) { 166 | if(j != party) { 167 | res_check.push_back(pool->enqueue([this, &input_mask, &open_bit_shares_for_plaintext_input_recv, j]() { 168 | for (int i = 0; i < len; i++) { 169 | if (party_assignment[i] == party) { 170 | block supposed_mac = Delta & select_mask[open_bit_shares_for_plaintext_input_recv[j][i].bit_share? 1 : 0]; 171 | supposed_mac ^= input_mask[i].key[j]; 172 | 173 | block provided_mac = open_bit_shares_for_plaintext_input_recv[j][i].mac; 174 | 175 | if(!cmpBlock(&supposed_mac, &provided_mac, 1)) { 176 | return true; 177 | } 178 | } 179 | } 180 | return false; 181 | })); 182 | } 183 | } 184 | if(joinNcleanCheat(res_check)) error("cheat in FlexIn's plaintext input mask!"); 185 | 186 | /* 187 | * broadcast the masked input 188 | */ 189 | vector masked_input_sent; // use char instead of bool because bools seem to fail for "data()" 190 | vector> masked_input_recv; 191 | masked_input_sent.resize(len); 192 | masked_input_recv.resize(nP + 1); 193 | for(int j = 1; j <= nP; j++) { 194 | masked_input_recv[j].resize(len); 195 | } 196 | 197 | for(int i = 0; i < len; i++) { 198 | if(party_assignment[i] == party) { 199 | masked_input_sent[i] = plaintext_assignment[i] ^ input_mask[i].bit_share; 200 | for(int j = 1; j <= nP; j++) { 201 | if(j != party) { 202 | masked_input_sent[i] = masked_input_sent[i] ^ open_bit_shares_for_plaintext_input_recv[j][i].bit_share; 203 | } 204 | } 205 | } 206 | } 207 | 208 | for (int i = 1; i <= nP; ++i) { 209 | for (int j = 1; j <= nP; ++j) { 210 | if ((i < j) and (i == party or j == party)) { 211 | int party2 = i + j - party; 212 | 213 | res.push_back(pool->enqueue([this, &masked_input_recv, party2]() { 214 | io->recv_data(party2, masked_input_recv[party2].data(), sizeof(char) * len); 215 | io->flush(party2); 216 | })); 217 | res.push_back(pool->enqueue([this, &masked_input_sent, party2]() { 218 | io->send_data(party2, masked_input_sent.data(), sizeof(char) * len); 219 | io->flush(party2); 220 | })); 221 | } 222 | } 223 | } 224 | joinNclean(res); 225 | 226 | vector masked_input; 227 | masked_input.resize(len); 228 | for(int i = 0; i < len; i++) { 229 | if(party_assignment[i] > 0) { 230 | int this_party = party_assignment[i]; 231 | if(this_party == party) { 232 | masked_input[i] = masked_input_sent[i]; 233 | } else { 234 | masked_input[i] = masked_input_recv[this_party][i]; 235 | } 236 | } 237 | } 238 | 239 | /* 240 | * secondly, handle the case party_assignment[] == -1 241 | */ 242 | 243 | /* 244 | * Compute the authenticated bit share to the new circuit 245 | * by XOR-ing with the input mask 246 | */ 247 | vector> authenticated_bitshares_new_circuit; 248 | for(int i = 0; i < len; i++) { 249 | AuthBitShare new_entry; 250 | memset(&new_entry, 0, sizeof(AuthBitShare)); 251 | if(party_assignment[i] == -1) { 252 | new_entry.bit_share = authenticated_share_assignment[i].bit_share ^ input_mask[i].bit_share; 253 | for (int j = 1; j <= nP; j++) { 254 | new_entry.key[j] = authenticated_share_assignment[i].key[j] ^ input_mask[i].key[j]; 255 | new_entry.mac[j] = authenticated_share_assignment[i].mac[j] ^ input_mask[i].mac[j]; 256 | } 257 | } 258 | authenticated_bitshares_new_circuit.emplace_back(new_entry); 259 | } 260 | 261 | //print_block(Delta); 262 | 263 | /* 264 | cout << "Debug the authenticated input" << endl; 265 | for(int i = 0; i < 10; i++){ 266 | if(party_assignment[i] == -1) { 267 | cout << "index: " << i << ", value: " << authenticated_share_assignment[i].bit_share << endl; 268 | cout << "mac: " << endl; 269 | for(int j = 1; j <= nP; j++) { 270 | if(j != party) { 271 | //cout << j << ": "; 272 | print_block(authenticated_share_assignment[i].mac[j]); 273 | } 274 | } 275 | cout << "key: " << endl; 276 | for(int j = 1; j <= nP; j++) { 277 | if(j != party) { 278 | //cout << j << ": "; 279 | print_block(authenticated_share_assignment[i].key[j]); 280 | print_block(authenticated_share_assignment[i].key[j] ^ Delta); 281 | } 282 | } 283 | cout << "=============" << endl; 284 | } 285 | } 286 | */ 287 | 288 | /* 289 | * Opening the authenticated shares 290 | */ 291 | vector> open_bit_shares_for_authenticated_bits_send; 292 | open_bit_shares_for_authenticated_bits_send.resize(nP + 1); 293 | 294 | for(int j = 1; j <= nP; j++) { 295 | if(j != party) { 296 | for(int i = 0; i < len; i++) { 297 | BitWithMac mbit{}; 298 | if(party_assignment[i] == -1) { 299 | mbit.bit_share = authenticated_bitshares_new_circuit[i].bit_share; 300 | mbit.mac = authenticated_bitshares_new_circuit[i].mac[j]; 301 | } 302 | open_bit_shares_for_authenticated_bits_send[j].push_back(mbit); 303 | } 304 | } 305 | } 306 | 307 | vector> open_bit_shares_for_authenticated_bits_recv; 308 | open_bit_shares_for_authenticated_bits_recv.resize(nP + 1); 309 | for(int j = 1; j <= nP; j++) { 310 | open_bit_shares_for_authenticated_bits_recv[j].resize(len); 311 | } 312 | 313 | for (int i = 1; i <= nP; ++i) { 314 | for (int j = 1; j <= nP; ++j) { 315 | if ((i < j) and (i == party or j == party)) { 316 | int party2 = i + j - party; 317 | 318 | res.push_back(pool->enqueue([this, &open_bit_shares_for_authenticated_bits_recv, party2]() { 319 | io->recv_data(party2, open_bit_shares_for_authenticated_bits_recv[party2].data(), sizeof(BitWithMac) * len); 320 | io->flush(party2); 321 | })); 322 | res.push_back(pool->enqueue([this, &open_bit_shares_for_authenticated_bits_send, party2]() { 323 | io->send_data(party2, open_bit_shares_for_authenticated_bits_send[party2].data(), sizeof(BitWithMac) * len); 324 | io->flush(party2); 325 | })); 326 | } 327 | } 328 | } 329 | joinNclean(res); 330 | 331 | /* 332 | * verify the input mask shares 333 | */ 334 | for (int j = 1; j <= nP; ++j) { 335 | if(j != party) { 336 | res_check.push_back(pool->enqueue([this, &authenticated_bitshares_new_circuit, &open_bit_shares_for_authenticated_bits_recv, j]() { 337 | for (int i = 0; i < len; i++) { 338 | if (party_assignment[i] == -1) { 339 | block supposed_mac = Delta & select_mask[open_bit_shares_for_authenticated_bits_recv[j][i].bit_share? 1 : 0]; 340 | supposed_mac ^= authenticated_bitshares_new_circuit[i].key[j]; 341 | 342 | block provided_mac = open_bit_shares_for_authenticated_bits_recv[j][i].mac; 343 | 344 | if(!cmpBlock(&supposed_mac, &provided_mac, 1)) { 345 | return true; 346 | } 347 | } 348 | } 349 | return false; 350 | })); 351 | } 352 | } 353 | if(joinNcleanCheat(res_check)) error("cheat in FlexIn's authenticated share input mask!"); 354 | 355 | /* 356 | * Reconstruct the authenticated shares 357 | */ 358 | for(int i = 0; i < len; i++) { 359 | if(party_assignment[i] == -1) { 360 | masked_input[i] = authenticated_bitshares_new_circuit[i].bit_share; 361 | for(int j = 1; j <= nP; j++) { 362 | if(j != party) { 363 | masked_input[i] = masked_input[i] ^ open_bit_shares_for_authenticated_bits_recv[j][i].bit_share; 364 | } 365 | } 366 | } 367 | } 368 | 369 | /* 370 | * thirdly, handle the case party_assignment[] = -2 371 | */ 372 | 373 | /* 374 | * Collect the masked input shares for un-authenticated bits 375 | */ 376 | vector open_bit_shares_for_unauthenticated_bits_send; 377 | open_bit_shares_for_unauthenticated_bits_send.resize(len); 378 | 379 | for(int i = 0; i < len; i++) { 380 | if(party_assignment[i] == -2) { 381 | open_bit_shares_for_unauthenticated_bits_send[i] = (plaintext_assignment[i] ^ input_mask[i].bit_share)? 1 : 0; 382 | } 383 | } 384 | 385 | vector> open_bit_shares_for_unauthenticated_bits_recv; 386 | open_bit_shares_for_unauthenticated_bits_recv.resize(nP + 1); 387 | for(int j = 1; j <= nP; j++) { 388 | open_bit_shares_for_unauthenticated_bits_recv[j].resize(len); 389 | } 390 | 391 | for (int i = 1; i <= nP; ++i) { 392 | for (int j = 1; j <= nP; ++j) { 393 | if ((i < j) and (i == party or j == party)) { 394 | int party2 = i + j - party; 395 | 396 | res.push_back(pool->enqueue([this, &open_bit_shares_for_unauthenticated_bits_recv, party2]() { 397 | io->recv_data(party2, open_bit_shares_for_unauthenticated_bits_recv[party2].data(), sizeof(char) * len); 398 | io->flush(party2); 399 | })); 400 | res.push_back(pool->enqueue([this, &open_bit_shares_for_unauthenticated_bits_send, party2]() { 401 | io->send_data(party2, open_bit_shares_for_unauthenticated_bits_send.data(), sizeof(char) * len); 402 | io->flush(party2); 403 | })); 404 | } 405 | } 406 | } 407 | joinNclean(res); 408 | 409 | /* 410 | * update the array of masked_input accordingly 411 | */ 412 | for(int i = 0; i < len; i++) { 413 | if(party_assignment[i] == -2) { 414 | masked_input[i] = open_bit_shares_for_unauthenticated_bits_send[i]; 415 | for(int j = 1; j <= nP; j++) { 416 | if(j != party) { 417 | masked_input[i] = masked_input[i] ^ (open_bit_shares_for_unauthenticated_bits_recv[j][i] == 1); 418 | } 419 | } 420 | } 421 | } 422 | 423 | /* 424 | * lastly, handle the case party_assignment[] = 0 425 | */ 426 | 427 | /* 428 | * broadcast the input mask and its MAC 429 | */ 430 | vector> open_bit_shares_for_public_input_send; 431 | open_bit_shares_for_public_input_send.resize(nP + 1); 432 | 433 | for(int j = 1; j <= nP; j++) { 434 | if(j != party) { 435 | for(int i = 0; i < len; i++) { 436 | BitWithMac mbit{}; 437 | if(party_assignment[i] == 0) { 438 | mbit.bit_share = input_mask[i].bit_share; 439 | mbit.mac = input_mask[i].mac[j]; 440 | } 441 | open_bit_shares_for_public_input_send[j].push_back(mbit); 442 | } 443 | } 444 | } 445 | 446 | vector> open_bit_shares_for_public_input_recv; 447 | open_bit_shares_for_public_input_recv.resize(nP + 1); 448 | for(int j = 1; j <= nP; j++) { 449 | open_bit_shares_for_public_input_recv[j].resize(len); 450 | } 451 | 452 | /* 453 | * exchange the opening of the input mask 454 | */ 455 | for (int i = 1; i <= nP; ++i) { 456 | for (int j = 1; j <= nP; ++j) { 457 | if ((i < j) and (i == party or j == party)) { 458 | int party2 = i + j - party; 459 | 460 | res.push_back(pool->enqueue([this, &open_bit_shares_for_public_input_recv, party2]() { 461 | io->recv_data(party2, open_bit_shares_for_public_input_recv[party2].data(), sizeof(BitWithMac) * len); 462 | io->flush(party2); 463 | })); 464 | res.push_back(pool->enqueue([this, &open_bit_shares_for_public_input_send, party2]() { 465 | io->send_data(party2, open_bit_shares_for_public_input_send[party2].data(), sizeof(BitWithMac) * len); 466 | io->flush(party2); 467 | })); 468 | } 469 | } 470 | } 471 | joinNclean(res); 472 | 473 | /* 474 | * verify the input mask 475 | */ 476 | for (int j = 1; j <= nP; ++j) { 477 | if(j != party) { 478 | res_check.push_back(pool->enqueue([this, &input_mask, &open_bit_shares_for_public_input_recv, j]() { 479 | for (int i = 0; i < len; i++) { 480 | if (party_assignment[i] == 0) { 481 | block supposed_mac = Delta & select_mask[open_bit_shares_for_public_input_recv[j][i].bit_share? 1 : 0]; 482 | supposed_mac ^= input_mask[i].key[j]; 483 | 484 | block provided_mac = open_bit_shares_for_public_input_recv[j][i].mac; 485 | 486 | if(!cmpBlock(&supposed_mac, &provided_mac, 1)) { 487 | return true; 488 | } 489 | } 490 | } 491 | return false; 492 | })); 493 | } 494 | } 495 | if(joinNcleanCheat(res_check)) error("cheat in FlexIn's public input mask!"); 496 | 497 | /* 498 | * update the masked input 499 | */ 500 | for(int i = 0; i < len; i++) { 501 | if(party_assignment[i] == 0) { 502 | masked_input[i] = plaintext_assignment[i] ^ input_mask[i].bit_share; 503 | for(int j = 1; j <= nP; j++) { 504 | if(j != party) { 505 | masked_input[i] = masked_input[i] ^ open_bit_shares_for_public_input_recv[j][i].bit_share; 506 | } 507 | } 508 | } 509 | } 510 | 511 | /* 512 | cout << "masked_input" << endl; 513 | for(int i = 0; i < len; i++) { 514 | cout << masked_input[i] << " "; 515 | } 516 | cout << endl; 517 | */ 518 | 519 | for(int i = 0; i < len; i++) { 520 | masked_input_ret[i] = masked_input[i]; 521 | } 522 | } 523 | 524 | int get_length() { 525 | return len; 526 | } 527 | }; 528 | 529 | template 530 | class FlexOut 531 | { 532 | public: 533 | 534 | int len{}; 535 | int party{}; 536 | 537 | bool cmpc_associated = false; 538 | ThreadPool* pool; 539 | bool *value; 540 | block *key[nP + 1]; 541 | block *mac[nP + 1]; 542 | block *eval_labels[nP + 1]; 543 | NetIOMP * io; 544 | block Delta; 545 | block *labels; 546 | 547 | vector party_assignment; 548 | // -1 represents an authenticated share, 549 | // 0 represents public output 550 | 551 | vector plaintext_results; // if `party` provides the value for this bit, the plaintext value is here 552 | vector> authenticated_share_results; // if this bit is from authenticated shares, the authenticated share is stored here 553 | 554 | FlexOut(int len, int party) { 555 | this->len = len; 556 | this->party = party; 557 | this->pool = pool; 558 | 559 | AuthBitShare empty_abit; 560 | memset(&empty_abit, 0, sizeof(AuthBitShare)); 561 | 562 | party_assignment.resize(len, 0); 563 | plaintext_results.resize(len, false); 564 | authenticated_share_results.resize(len, empty_abit); 565 | } 566 | 567 | ~FlexOut() { 568 | party_assignment.clear(); 569 | plaintext_results.clear(); 570 | authenticated_share_results.clear(); 571 | } 572 | 573 | void associate_cmpc(ThreadPool *associated_pool, bool *associated_value, block *associated_mac[nP + 1], block *associated_key[nP + 1], block *associated_eval_labels[nP + 1], block *associated_labels, NetIOMP *associated_io, block associated_Delta) { 574 | this->cmpc_associated = true; 575 | this->pool = associated_pool; 576 | this->value = associated_value; 577 | this->labels = associated_labels; 578 | for (int j = 1; j <= nP; j++) { 579 | this->mac[j] = associated_mac[j]; 580 | this->key[j] = associated_key[j]; 581 | } 582 | if (party == ALICE){ 583 | for (int j = 2; j <= nP; j++) { 584 | this->eval_labels[j] = associated_eval_labels[j]; 585 | } 586 | } 587 | this->io = associated_io; 588 | this->Delta = associated_Delta; 589 | } 590 | 591 | void assign_party(int pos, int which_party) { 592 | party_assignment[pos] = which_party; 593 | } 594 | 595 | bool get_plaintext_bit(int pos) { 596 | assert(party_assignment[pos] == party || party_assignment[pos] == 0); 597 | return plaintext_results[pos]; 598 | } 599 | 600 | AuthBitShare get_authenticated_bitshare(int pos) { 601 | assert(party_assignment[pos] == -1); 602 | return authenticated_share_results[pos]; 603 | } 604 | 605 | int get_length() { 606 | return len; 607 | } 608 | 609 | void output(bool *masked_input_ret, int output_shift) { 610 | assert(cmpc_associated); 611 | 612 | /* 613 | * Party 1 sends the labels of all the output wires out. 614 | */ 615 | vector output_wire_label_recv; 616 | output_wire_label_recv.resize(len); 617 | 618 | vector> res; 619 | 620 | if(party == ALICE) { 621 | vector> output_wire_label_send; 622 | output_wire_label_send.resize(nP + 1); 623 | 624 | for (int j = 2; j <= nP; j++) { 625 | output_wire_label_send[j].resize(len); 626 | for(int i = 0; i < len; i++) { 627 | output_wire_label_send[j][i] = eval_labels[j][output_shift + i]; 628 | } 629 | } 630 | 631 | for(int j = 2; j <= nP; j++) { 632 | res.push_back(pool->enqueue([this, &output_wire_label_send, j]() { 633 | io->send_data(j, output_wire_label_send[j].data(), sizeof(block) * len); 634 | io->flush(j); 635 | })); 636 | } 637 | joinNclean(res); 638 | }else { 639 | io->recv_data(ALICE, output_wire_label_recv.data(), sizeof(block) * len); 640 | io->flush(ALICE); 641 | } 642 | 643 | /* 644 | * Each party extracts x ^ r of each output wire 645 | */ 646 | vector masked_output; 647 | masked_output.resize(len); 648 | 649 | if(party == ALICE) { 650 | for(int i = 0; i < len; i++) { 651 | masked_output[i] = masked_input_ret[output_shift + i]; 652 | } 653 | } else { 654 | for(int i = 0; i < len; i++) { 655 | block cur_label = output_wire_label_recv[i]; 656 | block zero_label = labels[i + output_shift]; 657 | block one_label = zero_label ^ Delta; 658 | 659 | if(cmpBlock(&cur_label, &zero_label, 1)) { 660 | masked_output[i] = false; 661 | } else if(cmpBlock(&cur_label, &one_label, 1)) { 662 | masked_output[i] = true; 663 | } else { 664 | error("Output label mismatched.\n"); 665 | } 666 | } 667 | } 668 | 669 | /* 670 | * Decide the broadcasting of the shares of r, as well as their MAC 671 | */ 672 | vector> output_mask_send; 673 | output_mask_send.resize(nP + 1); 674 | for(int j = 1; j <= nP; j++) { 675 | BitWithMac empty_mbit{}; 676 | output_mask_send[j].resize(len, empty_mbit); 677 | } 678 | 679 | for(int i = 0; i < len; i++) { 680 | if(party_assignment[i] == -1) { 681 | // do nothing, just update the share (for the first party) later 682 | } else if(party_assignment[i] == 0) { 683 | // public output, all parties receive the mbit 684 | for(int j = 1; j <= nP; j++){ 685 | output_mask_send[j][i].bit_share = value[output_shift + i]; 686 | output_mask_send[j][i].mac = mac[j][output_shift + i]; 687 | } 688 | } else { 689 | // only one party is supposed to receive the mbit 690 | int cur_party = party_assignment[i]; 691 | output_mask_send[cur_party][i].bit_share = value[output_shift + i]; 692 | output_mask_send[cur_party][i].mac = mac[cur_party][output_shift + i]; 693 | } 694 | } 695 | 696 | /* 697 | * Exchange the output mask 698 | */ 699 | vector> output_mask_recv; 700 | output_mask_recv.resize(nP + 1); 701 | for(int j = 1; j <= nP; j++) { 702 | output_mask_recv[j].resize(len); 703 | } 704 | 705 | for (int i = 1; i <= nP; ++i) { 706 | for (int j = 1; j <= nP; ++j) { 707 | if ((i < j) and (i == party or j == party)) { 708 | int party2 = i + j - party; 709 | 710 | res.push_back(pool->enqueue([this, &output_mask_recv, party2]() { 711 | io->recv_data(party2, output_mask_recv[party2].data(), sizeof(BitWithMac) * len); 712 | io->flush(party2); 713 | })); 714 | res.push_back(pool->enqueue([this, &output_mask_send, party2]() { 715 | io->send_data(party2, output_mask_send[party2].data(), sizeof(BitWithMac) * len); 716 | io->flush(party2); 717 | })); 718 | } 719 | } 720 | } 721 | joinNclean(res); 722 | 723 | /* 724 | * Verify the output mask 725 | */ 726 | vector> res_check; 727 | for (int j = 1; j <= nP; ++j) { 728 | if(j != party) { 729 | res_check.push_back(pool->enqueue([this, &output_mask_recv, j, output_shift]() { 730 | for (int i = 0; i < len; i++) { 731 | if (party_assignment[i] == party || party_assignment[i] == 0) { 732 | block supposed_mac = Delta & select_mask[output_mask_recv[j][i].bit_share? 1 : 0]; 733 | supposed_mac ^= key[j][output_shift + i]; 734 | 735 | block provided_mac = output_mask_recv[j][i].mac; 736 | 737 | if(!cmpBlock(&supposed_mac, &provided_mac, 1)) { 738 | return true; 739 | } 740 | } 741 | } 742 | return false; 743 | })); 744 | } 745 | } 746 | if(joinNcleanCheat(res_check)) error("cheat in FlexOut's output mask!"); 747 | 748 | /* 749 | * Handle the case party_assignment[] = -1 750 | */ 751 | if(party == ALICE) { 752 | for(int i = 0; i < len; i++) { 753 | if(party_assignment[i] == -1) { 754 | authenticated_share_results[i].bit_share = value[output_shift + i] ^ masked_output[i]; 755 | for(int j = 1; j <= nP; j++) { 756 | if(j != party) { 757 | authenticated_share_results[i].mac[j] = mac[j][output_shift + i]; 758 | authenticated_share_results[i].key[j] = key[j][output_shift + i]; 759 | } 760 | } 761 | } 762 | } 763 | } else { 764 | for(int i = 0; i < len; i++) { 765 | if(party_assignment[i] == -1) { 766 | authenticated_share_results[i].bit_share = value[output_shift + i]; 767 | for(int j = 1; j <= nP; j++) { 768 | if(j != party) { 769 | authenticated_share_results[i].mac[j] = mac[j][output_shift + i]; 770 | if(j == ALICE) { 771 | authenticated_share_results[i].key[j] = 772 | key[j][output_shift + i] ^ (Delta & select_mask[masked_output[i] ? 1 : 0]); 773 | // change the MAC key for the first party 774 | } else { 775 | authenticated_share_results[i].key[j] = key[j][output_shift + i]; 776 | } 777 | } 778 | } 779 | } 780 | } 781 | } 782 | 783 | //print_block(Delta); 784 | 785 | /* 786 | cout << "Debug the authenticated output" << endl; 787 | for(int i = 0; i < 10; i++){ 788 | if(party_assignment[i] == -1) { 789 | cout << "index: " << i << ", value: " << authenticated_share_results[i].bit_share << endl; 790 | cout << "mac: " << endl; 791 | for(int j = 1; j <= nP; j++) { 792 | if(j != party) { 793 | //cout << j << ": "; 794 | print_block(authenticated_share_results[i].mac[j]); 795 | } 796 | } 797 | cout << "key: " << endl; 798 | for(int j = 1; j <= nP; j++) { 799 | if(j != party) { 800 | //cout << j << ": "; 801 | print_block(authenticated_share_results[i].key[j]); 802 | print_block(authenticated_share_results[i].key[j] ^ Delta); 803 | } 804 | } 805 | cout << "=============" << endl; 806 | } 807 | } 808 | */ 809 | 810 | /* 811 | * Handle the case party_assignment[] = 0 or == party 812 | */ 813 | for(int i = 0; i < len; i++) { 814 | if(party_assignment[i] == 0 || party_assignment[i] == party) { 815 | plaintext_results[i] = value[output_shift + i] ^ masked_output[i]; 816 | for(int j = 1; j <= nP; j++) { 817 | if(j != party) { 818 | plaintext_results[i] = plaintext_results[i] ^ output_mask_recv[j][i].bit_share; 819 | } 820 | } 821 | } 822 | } 823 | } 824 | }; 825 | 826 | #endif //EMP_AGMPC_FLEXIBLE_INPUT_OUTPUT_H 827 | -------------------------------------------------------------------------------- /emp-agmpc/fpremp.h: -------------------------------------------------------------------------------- 1 | //TODO: check MACs 2 | #ifndef FPRE_MP_H__ 3 | #define FPRE_MP_H__ 4 | #include 5 | #include 6 | #include "abitmp.h" 7 | #include "netmp.h" 8 | #include "cmpc_config.h" 9 | 10 | using namespace emp; 11 | template 12 | class FpreMP { public: 13 | ThreadPool *pool; 14 | int party; 15 | NetIOMP * io; 16 | ABitMP* abit; 17 | block Delta; 18 | CRH * prps; 19 | CRH * prps2; 20 | PRG * prgs; 21 | PRG prg; 22 | int ssp; 23 | FpreMP(NetIOMP * io[2], ThreadPool * pool, int party, bool * _delta = nullptr, int ssp = 40) { 24 | this->party = party; 25 | this->pool = pool; 26 | this->io = io[0]; 27 | this ->ssp = ssp; 28 | abit = new ABitMP(io[1], pool, party, _delta, ssp); 29 | Delta = abit->Delta; 30 | prps = new CRH[nP+1]; 31 | prps2 = new CRH[nP+1]; 32 | prgs = new PRG[nP+1]; 33 | } 34 | ~FpreMP(){ 35 | delete[] prps; 36 | delete[] prps2; 37 | delete[] prgs; 38 | delete abit; 39 | } 40 | int get_bucket_size(int size) { 41 | size = max(size, 320); 42 | int batch_size = ((size+2-1)/2)*2; 43 | if(batch_size >= 280*1000) 44 | return 3; 45 | else if(batch_size >= 3100) 46 | return 4; 47 | else return 5; 48 | } 49 | void compute(block * MAC[nP+1], block * KEY[nP+1], bool * r, int length) { 50 | int64_t bucket_size = get_bucket_size(length); 51 | block * tMAC[nP+1]; 52 | block * tKEY[nP+1]; 53 | block * tKEYphi[nP+1]; 54 | block * tMACphi[nP+1]; 55 | block * phi; 56 | block *X [nP+1]; 57 | bool *tr = new bool[length*bucket_size*3+3*ssp]; 58 | phi = new block[length*bucket_size]; 59 | bool *s[nP+1], *e = new bool[length*bucket_size]; 60 | for(int i = 1; i <= nP; ++i) { 61 | tMAC[i] = new block[length*bucket_size*3+3*ssp]; 62 | tKEY[i] = new block[length*bucket_size*3+3*ssp]; 63 | tKEYphi[i] = new block[length*bucket_size+3*ssp]; 64 | tMACphi[i] = new block[length*bucket_size+3*ssp]; 65 | X[i] = new block[ssp]; 66 | } 67 | for(int i = 0; i <= nP; ++i) { 68 | s[i] = new bool[length*bucket_size]; 69 | memset(s[i], 0, length*bucket_size); 70 | } 71 | prg.random_bool(tr, length*bucket_size*3+3*ssp); 72 | // memset(tr, false, length*bucket_size*3+3*ssp); 73 | abit->compute(tMAC, tKEY, tr, length*bucket_size*3 + 3*ssp); 74 | vector> res; 75 | 76 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if (i < j ) { 77 | if(i == party) { 78 | res.push_back(pool->enqueue([this, tKEY, tr, s, length, bucket_size, j]() { 79 | prgs[j].random_bool(s[j], length*bucket_size); 80 | for(int k = 0; k < length*bucket_size; ++k) { 81 | uint8_t data = garble(tKEY[j], tr, s[j], k, j); 82 | io->send_data(j, &data, 1); 83 | s[j][k] = (s[j][k] != (tr[3*k] and tr[3*k+1])); 84 | } 85 | io->flush(j); 86 | })); 87 | } else if (j == party) { 88 | res.push_back(pool->enqueue([this, tMAC, tr, s, length, bucket_size, i]() { 89 | for(int k = 0; k < length*bucket_size; ++k) { 90 | uint8_t data = 0; 91 | io->recv_data(i, &data, 1); 92 | bool tmp = evaluate(data, tMAC[i], tr, k, i); 93 | s[i][k] = (tmp != (tr[3*k] and tr[3*k+1])); 94 | } 95 | })); 96 | } 97 | } 98 | joinNclean(res); 99 | for(int k = 0; k < length*bucket_size; ++k) { 100 | s[0][k] = (tr[3*k] and tr[3*k+1]); 101 | for(int i = 1; i <= nP; ++i) 102 | if (i != party) { 103 | s[0][k] = (s[0][k] != s[i][k]); 104 | } 105 | e[k] = (s[0][k] != tr[3*k+2]); 106 | tr[3*k+2] = s[0][k]; 107 | } 108 | 109 | #ifdef __debug 110 | check_correctness(io, tr, length*bucket_size, party); 111 | #endif 112 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 113 | int party2 = i + j - party; 114 | res.push_back(pool->enqueue([this, e, length, bucket_size, party2]() { 115 | io->send_data(party2, e, length*bucket_size); 116 | io->flush(party2); 117 | })); 118 | res.push_back(pool->enqueue([this, tKEY, length, bucket_size, party2]() { 119 | bool * tmp = new bool[length*bucket_size]; 120 | io->recv_data(party2, tmp, length*bucket_size); 121 | for(int k = 0; k < length*bucket_size; ++k) { 122 | if(tmp[k]) 123 | tKEY[party2][3*k+2] = tKEY[party2][3*k+2] ^ Delta; 124 | } 125 | delete[] tmp; 126 | })); 127 | } 128 | joinNclean(res); 129 | #ifdef __debug 130 | check_MAC(io, tMAC, tKEY, tr, Delta, length*bucket_size*3, party); 131 | #endif 132 | auto ret = abit->check(tMAC, tKEY, tr, length*bucket_size*3 + 3*ssp); 133 | ret.get(); 134 | //check compute phi 135 | for(int k = 0; k < length*bucket_size; ++k) { 136 | phi[k] = zero_block; 137 | for(int i = 1; i <= nP; ++i) if (i != party) { 138 | phi[k] = phi[k] ^ tKEY[i][3*k+1]; 139 | phi[k] = phi[k] ^ tMAC[i][3*k+1]; 140 | } 141 | if(tr[3*k+1])phi[k] = phi[k] ^ Delta; 142 | } 143 | 144 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 145 | int party2 = i + j - party; 146 | res.push_back(pool->enqueue([this, tKEY, tKEYphi, phi, length, bucket_size, party2]() { 147 | block bH[2], tmpH[2]; 148 | for(int k = 0; k < length*bucket_size; ++k) { 149 | bH[0] = tKEY[party2][3*k]; 150 | bH[1] = bH[0] ^ Delta; 151 | HnID(prps+party2, bH, bH, 2*k, 2, tmpH); 152 | tKEYphi[party2][k] = bH[0]; 153 | bH[1] = bH[0] ^ bH[1]; 154 | bH[1] = phi[k] ^ bH[1]; 155 | io->send_data(party2, &bH[1], sizeof(block)); 156 | } 157 | io->flush(party2); 158 | })); 159 | res.push_back(pool->enqueue([this, tMAC, tMACphi, tr, length, bucket_size, party2]() { 160 | block bH; 161 | for(int k = 0; k < length*bucket_size; ++k) { 162 | io->recv_data(party2, &bH, sizeof(block)); 163 | block hin = sigma(tMAC[party2][3*k]) ^ makeBlock(0, 2*k+tr[3*k]); 164 | tMACphi[party2][k] = prps2[party2].H(hin); 165 | if(tr[3*k])tMACphi[party2][k] = tMACphi[party2][k] ^ bH; 166 | } 167 | })); 168 | } 169 | joinNclean(res); 170 | 171 | bool * xs = new bool[length*bucket_size]; 172 | for(int i = 0; i < length*bucket_size; ++i) xs[i] = tr[3*i]; 173 | 174 | #ifdef __debug 175 | check_MAC_phi(tMACphi, tKEYphi, phi, xs, length*bucket_size); 176 | #endif 177 | //tKEYphti use as H 178 | for(int k = 0; k < length*bucket_size; ++k) { 179 | tKEYphi[party][k] = zero_block; 180 | for(int i = 1; i <= nP; ++i) if (i != party) { 181 | tKEYphi[party][k] = tKEYphi[party][k] ^ tKEYphi[i][k]; 182 | tKEYphi[party][k] = tKEYphi[party][k] ^ tMACphi[i][k]; 183 | tKEYphi[party][k] = tKEYphi[party][k] ^ tKEY[i][3*k+2]; 184 | tKEYphi[party][k] = tKEYphi[party][k] ^ tMAC[i][3*k+2]; 185 | } 186 | if(tr[3*k]) tKEYphi[party][k] = tKEYphi[party][k] ^ phi[k]; 187 | if(tr[3*k+2])tKEYphi[party][k] = tKEYphi[party][k] ^ Delta; 188 | } 189 | 190 | #ifdef __debug 191 | check_zero(tKEYphi[party], length*bucket_size); 192 | #endif 193 | 194 | block prg_key = sampleRandom(io, &prg, pool, party); 195 | PRG prgf(&prg_key); 196 | char (*dgst)[Hash::DIGEST_SIZE] = new char[nP+1][Hash::DIGEST_SIZE]; 197 | bool * tmp = new bool[length*bucket_size]; 198 | for(int i = 0; i < ssp; ++i) { 199 | prgf.random_bool(tmp, length*bucket_size); 200 | X[party][i] = inProd(tmp, tKEYphi[party], length*bucket_size); 201 | } 202 | Hash::hash_once(dgst[party], X[party], sizeof(block)*ssp); 203 | 204 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 205 | int party2 = i + j - party; 206 | res.push_back(pool->enqueue([this, dgst, party2]() { 207 | io->send_data(party2, dgst[party], Hash::DIGEST_SIZE); 208 | io->recv_data(party2, dgst[party2], Hash::DIGEST_SIZE); 209 | })); 210 | } 211 | joinNclean(res); 212 | vector> res2; 213 | 214 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 215 | int party2 = i + j - party; 216 | res2.push_back(pool->enqueue([this, X, dgst, party2]() -> bool { 217 | io->send_data(party2, X[party], sizeof(block)*ssp); 218 | io->recv_data(party2, X[party2], sizeof(block)*ssp); 219 | char tmp[Hash::DIGEST_SIZE]; 220 | Hash::hash_once(tmp, X[party2], sizeof(block)*ssp); 221 | return strncmp(tmp, dgst[party2], Hash::DIGEST_SIZE)!=0; 222 | })); 223 | } 224 | if(joinNcleanCheat(res2)) error("commitment"); 225 | 226 | for(int i = 2; i <= nP; ++i) 227 | xorBlocks_arr(X[1], X[1], X[i], ssp); 228 | for(int i = 0; i < ssp; ++i)X[2][i] = zero_block; 229 | if(!cmpBlock(X[1], X[2], ssp)) error("AND check"); 230 | 231 | //land -> and 232 | block S = sampleRandom(io, &prg, pool, party); 233 | 234 | int * ind = new int[length*bucket_size]; 235 | int *location = new int[length*bucket_size]; 236 | bool * d[nP+1]; 237 | for(int i = 1; i <= nP; ++i) 238 | d[i] = new bool[length*(bucket_size-1)]; 239 | for(int i = 0; i < length*bucket_size; ++i) 240 | location[i] = i; 241 | PRG prg2(&S); 242 | prg2.random_data(ind, length*bucket_size*4); 243 | for(int i = length*bucket_size-1; i>=0; --i) { 244 | int index = ind[i]%(i+1); 245 | index = index>0? index:(-1*index); 246 | int tmp = location[i]; 247 | location[i] = location[index]; 248 | location[index] = tmp; 249 | } 250 | delete[] ind; 251 | 252 | for(int i = 0; i < length; ++i) { 253 | for(int j = 0; j < bucket_size-1; ++j) 254 | d[party][(bucket_size-1)*i+j] = tr[3*location[i*bucket_size]+1] != tr[3*location[i*bucket_size+1+j]+1]; 255 | for(int j = 1; j <= nP; ++j) if (j!= party) { 256 | memcpy(MAC[j]+3*i, tMAC[j]+3*location[i*bucket_size], 3*sizeof(block)); 257 | memcpy(KEY[j]+3*i, tKEY[j]+3*location[i*bucket_size], 3*sizeof(block)); 258 | for(int k = 1; k < bucket_size; ++k) { 259 | MAC[j][3*i] = MAC[j][3*i] ^ tMAC[j][3*location[i*bucket_size+k]]; 260 | KEY[j][3*i] = KEY[j][3*i] ^ tKEY[j][3*location[i*bucket_size+k]]; 261 | 262 | MAC[j][3*i+2] = MAC[j][3*i+2] ^ tMAC[j][3*location[i*bucket_size+k]+2]; 263 | KEY[j][3*i+2] = KEY[j][3*i+2] ^ tKEY[j][3*location[i*bucket_size+k]+2]; 264 | } 265 | } 266 | memcpy(r+3*i, tr+3*location[i*bucket_size], 3); 267 | for(int k = 1; k < bucket_size; ++k) { 268 | r[3*i] = r[3*i] != tr[3*location[i*bucket_size+k]]; 269 | r[3*i+2] = r[3*i+2] != tr[3*location[i*bucket_size+k]+2]; 270 | } 271 | } 272 | 273 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 274 | int party2 = i + j - party; 275 | res.push_back(pool->enqueue([this, d, length, bucket_size, party2]() { 276 | io->send_data(party2, d[party], (bucket_size-1)*length); 277 | io->flush(party2); 278 | })); 279 | res.push_back(pool->enqueue([this, d, length, bucket_size, party2]() { 280 | io->recv_data(party2, d[party2], (bucket_size-1)*length); 281 | })); 282 | } 283 | joinNclean(res); 284 | for(int i = 2; i <= nP; ++i) 285 | for(int j = 0; j < (bucket_size-1)*length; ++j) 286 | d[1][j] = d[1][j]!=d[i][j]; 287 | 288 | for(int i = 0; i < length; ++i) { 289 | for(int j = 1; j <= nP; ++j)if (j!= party) { 290 | for(int k = 1; k < bucket_size; ++k) 291 | if(d[1][(bucket_size-1)*i+k-1]) { 292 | MAC[j][3*i+2] = MAC[j][3*i+2] ^ tMAC[j][3*location[i*bucket_size+k]]; 293 | KEY[j][3*i+2] = KEY[j][3*i+2] ^ tKEY[j][3*location[i*bucket_size+k]]; 294 | } 295 | } 296 | for(int k = 1; k < bucket_size; ++k) 297 | if(d[1][(bucket_size-1)*i+k-1]) { 298 | r[3*i+2] = r[3*i+2] != tr[3*location[i*bucket_size+k]]; 299 | } 300 | } 301 | 302 | #ifdef __debug 303 | check_MAC(io, MAC, KEY, r, Delta, length*3, party); 304 | check_correctness(io, r, length, party); 305 | #endif 306 | 307 | // ret.get(); 308 | delete[] tr; 309 | delete[] phi; 310 | delete[] e; 311 | delete[] dgst; 312 | delete[] tmp; 313 | delete[] location; 314 | delete[] xs; 315 | for(int i = 1; i <= nP; ++i) { 316 | delete[] tMAC[i]; 317 | delete[] tKEY[i]; 318 | delete[] tMACphi[i]; 319 | delete[] tKEYphi[i]; 320 | delete[] X[i]; 321 | delete[] s[i]; 322 | delete[] d[i]; 323 | } 324 | delete[] s[0]; 325 | } 326 | 327 | //TODO: change to justGarble 328 | uint8_t garble(block * KEY, bool * r, bool * r2, int i, int I) { 329 | uint8_t data = 0; 330 | block tmp[4], tmp2[4], tmpH[4]; 331 | tmp[0] = KEY[3*i]; 332 | tmp[1] = tmp[0] ^ Delta; 333 | tmp[2] = KEY[3*i+1]; 334 | tmp[3] = tmp[2] ^ Delta; 335 | HnID(prps+I, tmp, tmp, 4*i, 4, tmpH); 336 | 337 | tmp2[0] = tmp[0] ^ tmp[2]; 338 | tmp2[1] = tmp[1] ^ tmp[2]; 339 | tmp2[2] = tmp[0] ^ tmp[3]; 340 | tmp2[3] = tmp[1] ^ tmp[3]; 341 | 342 | data = LSB(tmp2[0]); 343 | data |= (LSB(tmp2[1])<<1); 344 | data |= (LSB(tmp2[2])<<2); 345 | data |= (LSB(tmp2[3])<<3); 346 | if ( ((false != r[3*i] ) && (false != r[3*i+1])) != r2[i] ) 347 | data= data ^ 0x1; 348 | if ( ((true != r[3*i] ) && (false != r[3*i+1])) != r2[i] ) 349 | data = data ^ 0x2; 350 | if ( ((false != r[3*i] ) && (true != r[3*i+1])) != r2[i] ) 351 | data = data ^ 0x4; 352 | if ( ((true != r[3*i] ) && (true != r[3*i+1])) != r2[i] ) 353 | data = data ^ 0x8; 354 | return data; 355 | } 356 | bool evaluate(uint8_t tmp, block * MAC, bool * r, int i, int I) { 357 | block hin = sigma(MAC[3*i]) ^ makeBlock(0, 4*i + r[3*i]); 358 | block hin2 = sigma(MAC[3*i+1]) ^ makeBlock(0, 4*i + 2 + r[3*i+1]); 359 | block bH = prps[I].H(hin) ^ prps[I].H(hin2); 360 | uint8_t res = LSB(bH); 361 | tmp >>= (r[3*i+1]*2+r[3*i]); 362 | return (tmp&0x1) != (res&0x1); 363 | } 364 | 365 | void check_MAC_phi(block * MAC[nP+1], block * KEY[nP+1], block * phi, bool * r, int length) { 366 | block * tmp = new block[length]; 367 | block *tD = new block[length]; 368 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if (i < j) { 369 | if(party == i) { 370 | io->send_data(j, phi, length*sizeof(block)); 371 | io->send_data(j, KEY[j], sizeof(block)*length); 372 | io->flush(j); 373 | } else if(party == j) { 374 | io->recv_data(i, tD, length*sizeof(block)); 375 | io->recv_data(i, tmp, sizeof(block)*length); 376 | for(int k = 0; k < length; ++k) { 377 | if(r[k])tmp[k] = tmp[k] ^ tD[k]; 378 | } 379 | if(!cmpBlock(MAC[i], tmp, length)) 380 | error("check_MAC_phi failed!"); 381 | } 382 | } 383 | delete[] tmp; 384 | delete[] tD; 385 | if(party == 1) 386 | cerr<<"check_MAC_phi pass!\n"<recv_data(i, tmp2, l*sizeof(block)); 397 | xorBlocks_arr(tmp1, tmp1, tmp2, l); 398 | } 399 | block z = zero_block; 400 | for(int i = 0; i < l; ++i) 401 | if(!cmpBlock(&z, &tmp1[i], 1)) 402 | error("check sum zero failed!"); 403 | cerr<<"check zero sum pass!\n"<send_data(1, b, l*sizeof(block)); 408 | io->flush(1); 409 | } 410 | } 411 | void HnID(CRH* crh, block*out, block* in, uint64_t id, int length, block * scratch = nullptr) { 412 | bool del = false; 413 | if(scratch == nullptr) { 414 | del = true; 415 | scratch = new block[length]; 416 | } 417 | for(int i = 0; i < length; ++i){ 418 | out[i] = scratch[i] = sigma(in[i]) ^ makeBlock(0, id); 419 | ++id; 420 | } 421 | crh->permute_block(scratch, length); 422 | xorBlocks_arr(out, scratch, out, length); 423 | if(del) { 424 | delete[] scratch; 425 | scratch = nullptr; 426 | } 427 | } 428 | }; 429 | #endif// FPRE_H__ 430 | -------------------------------------------------------------------------------- /emp-agmpc/helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELPER 2 | #define __HELPER 3 | #include 4 | #include "cmpc_config.h" 5 | #include "netmp.h" 6 | #include 7 | using namespace emp; 8 | using std::future; 9 | using std::cout; 10 | using std::max; 11 | using std::cerr; 12 | using std::endl; 13 | using std::flush; 14 | 15 | const static block inProdTableBlock[] = {zero_block, all_one_block}; 16 | 17 | block inProd(bool * b, block * blk, int length) { 18 | block res = zero_block; 19 | for(int i = 0; i < length; ++i) 20 | // if(b[i]) 21 | // res = res ^ blk[i]; 22 | res = res ^ (inProdTableBlock[b[i]] & blk[i]); 23 | return res; 24 | } 25 | #ifdef __GNUC__ 26 | #ifndef __clang__ 27 | #pragma GCC push_options 28 | #pragma GCC optimize ("unroll-loops") 29 | #endif 30 | #endif 31 | 32 | template 33 | void inProdhelp(block *Ms, bool * tmp[ssp], block * MAC, int i) { 34 | for(int j = 0; j < ssp; ++j) 35 | Ms[j] = Ms[j] ^ (inProdTableBlock[tmp[j][i]] & MAC[i]); 36 | } 37 | #ifdef __GNUC__ 38 | #ifndef __clang__ 39 | #pragma GCC pop_options 40 | #endif 41 | #endif 42 | 43 | 44 | template 45 | void inProds(block *Ms, bool * tmp[ssp], block * MAC, int length) { 46 | memset(Ms, 0, sizeof(block)*ssp); 47 | for(int i = 0; i < length; ++i) { 48 | inProdhelp(Ms, tmp, MAC, i); 49 | } 50 | } 51 | bool inProd(bool * b, bool* b2, int length) { 52 | bool res = false; 53 | for(int i = 0; i < length; ++i) 54 | res = (res != (b[i] and b2[i])); 55 | return res; 56 | } 57 | 58 | template 59 | void joinNclean(vector>& res) { 60 | for(auto &v: res) v.get(); 61 | res.clear(); 62 | } 63 | 64 | bool joinNcleanCheat(vector>& res) { 65 | bool cheat = false; 66 | for(auto &v: res) cheat = cheat or v.get(); 67 | res.clear(); 68 | return cheat; 69 | } 70 | 71 | void send_bool(NetIO * io, const bool * data, int length) { 72 | if(lan_network) { 73 | io->send_data(data, length); 74 | return; 75 | } 76 | for(int i = 0; i < length;) { 77 | uint64_t tmp = 0; 78 | for(int j = 0; j < 64 and i < length; ++i,++j) { 79 | if(data[i]) 80 | tmp|=(0x1ULL<send_data(&tmp, 8); 83 | } 84 | } 85 | 86 | void recv_bool(NetIO * io, bool * data, int length) { 87 | if(lan_network) { 88 | io->recv_data(data, length); 89 | return; 90 | } 91 | for(int i = 0; i < length;) { 92 | uint64_t tmp = 0; 93 | io->recv_data(&tmp, 8); 94 | for(int j = 63; j >= 0 and i < length; ++i,--j) { 95 | data[i] = (tmp&0x1) == 0x1; 96 | tmp>>=1; 97 | } 98 | } 99 | } 100 | 101 | template 102 | void send_partial_block(NetIO * io, const block * data, int length) { 103 | for(int i = 0; i < length; ++i) { 104 | io->send_data(&(data[i]), B); 105 | } 106 | } 107 | 108 | template 109 | void recv_partial_block(NetIO * io, block * data, int length) { 110 | for(int i = 0; i < length; ++i) { 111 | io->recv_data(&(data[i]), B); 112 | } 113 | } 114 | 115 | inline uint8_t LSB(block & b) { 116 | return _mm_extract_epi8(b, 0) & 0x1; 117 | } 118 | 119 | template 120 | block sampleRandom(NetIOMP * io, PRG * prg, ThreadPool * pool, int party) { 121 | vector> res; 122 | vector> res2; 123 | char (*dgst)[Hash::DIGEST_SIZE] = new char[nP+1][Hash::DIGEST_SIZE]; 124 | block *S = new block[nP+1]; 125 | prg->random_block(&S[party], 1); 126 | Hash::hash_once(dgst[party], &S[party], sizeof(block)); 127 | 128 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 129 | int party2 = i + j - party; 130 | res.push_back(pool->enqueue([dgst, io, party, party2]() { 131 | io->send_data(party2, dgst[party], Hash::DIGEST_SIZE); 132 | io->recv_data(party2, dgst[party2], Hash::DIGEST_SIZE); 133 | })); 134 | } 135 | joinNclean(res); 136 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 137 | int party2 = i + j - party; 138 | res2.push_back(pool->enqueue([io, S, dgst, party, party2]() -> bool { 139 | io->send_data(party2, &S[party], sizeof(block)); 140 | io->recv_data(party2, &S[party2], sizeof(block)); 141 | char tmp[Hash::DIGEST_SIZE]; 142 | Hash::hash_once(tmp, &S[party2], sizeof(block)); 143 | return strncmp(tmp, dgst[party2], Hash::DIGEST_SIZE)!=0; 144 | })); 145 | } 146 | bool cheat = joinNcleanCheat(res2); 147 | if(cheat) { 148 | cout <<"cheat in sampleRandom\n"< 160 | void check_MAC(NetIOMP * io, block * MAC[nP+1], block * KEY[nP+1], bool * r, block Delta, int length, int party) { 161 | block * tmp = new block[length]; 162 | block tD; 163 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if (i < j) { 164 | if(party == i) { 165 | io->send_data(j, &Delta, sizeof(block)); 166 | io->send_data(j, KEY[j], sizeof(block)*length); 167 | io->flush(j); 168 | } else if(party == j) { 169 | io->recv_data(i, &tD, sizeof(block)); 170 | io->recv_data(i, tmp, sizeof(block)*length); 171 | for(int k = 0; k < length; ++k) { 172 | if(r[k])tmp[k] = tmp[k] ^ tD; 173 | } 174 | if(!cmpBlock(MAC[i], tmp, length)) 175 | error("check_MAC failed!"); 176 | } 177 | } 178 | delete[] tmp; 179 | if(party == 1) 180 | cerr<<"check_MAC pass!\n"< 184 | void check_correctness(NetIOMP* io, bool * r, int length, int party) { 185 | if (party == 1) { 186 | bool * tmp1 = new bool[length*3]; 187 | bool * tmp2 = new bool[length*3]; 188 | memcpy(tmp1, r, length*3); 189 | for(int i = 2; i <= nP; ++i) { 190 | io->recv_data(i, tmp2, length*3); 191 | for(int k = 0; k < length*3; ++k) 192 | tmp1[k] = (tmp1[k] != tmp2[k]); 193 | } 194 | for(int k = 0; k < length; ++k) { 195 | if((tmp1[3*k] and tmp1[3*k+1]) != tmp1[3*k+2]) 196 | error("check_correctness failed!"); 197 | } 198 | delete[] tmp1; 199 | delete[] tmp2; 200 | cerr<<"check_correctness pass!\n"<send_data(1, r, length*3); 203 | io->flush(1); 204 | } 205 | } 206 | 207 | inline const char* hex_char_to_bin(char c) { 208 | switch(toupper(c)) { 209 | case '0': return "0000"; 210 | case '1': return "0001"; 211 | case '2': return "0010"; 212 | case '3': return "0011"; 213 | case '4': return "0100"; 214 | case '5': return "0101"; 215 | case '6': return "0110"; 216 | case '7': return "0111"; 217 | case '8': return "1000"; 218 | case '9': return "1001"; 219 | case 'A': return "1010"; 220 | case 'B': return "1011"; 221 | case 'C': return "1100"; 222 | case 'D': return "1101"; 223 | case 'E': return "1110"; 224 | case 'F': return "1111"; 225 | default: return "0"; 226 | } 227 | } 228 | 229 | 230 | inline std::string hex_to_binary(std::string hex) { 231 | std::string bin; 232 | for(unsigned i = 0; i != hex.length(); ++i) 233 | bin += hex_char_to_bin(hex[i]); 234 | return bin; 235 | } 236 | 237 | #endif// __HELPER 238 | 239 | -------------------------------------------------------------------------------- /emp-agmpc/mpc.h: -------------------------------------------------------------------------------- 1 | #ifndef CMPC_H__ 2 | #define CMPC_H__ 3 | #include "fpremp.h" 4 | #include "abitmp.h" 5 | #include "netmp.h" 6 | #include "flexible_input_output.h" 7 | #include 8 | using namespace emp; 9 | 10 | template 11 | class CMPC { public: 12 | const static int SSP = 5;//5*8 in fact... 13 | const block MASK = makeBlock(0x0ULL, 0xFFFFFULL); 14 | FpreMP* fpre = nullptr; 15 | block* mac[nP+1]; 16 | block* key[nP+1]; 17 | bool* value; 18 | 19 | block * preprocess_mac[nP+1]; 20 | block * preprocess_key[nP+1]; 21 | bool* preprocess_value; 22 | 23 | block * sigma_mac[nP+1]; 24 | block * sigma_key[nP+1]; 25 | bool * sigma_value; 26 | 27 | block * ANDS_mac[nP+1]; 28 | block * ANDS_key[nP+1]; 29 | bool * ANDS_value; 30 | 31 | block * labels; 32 | BristolFormat * cf; 33 | NetIOMP * io; 34 | int num_ands = 0, num_in; 35 | int party, total_pre, ssp; 36 | ThreadPool * pool; 37 | block Delta; 38 | 39 | block (*GTM)[4][nP+1]; 40 | block (*GTK)[4][nP+1]; 41 | bool (*GTv)[4]; 42 | block (*GT)[nP+1][4][nP+1]; 43 | block * eval_labels[nP+1]; 44 | PRP prp; 45 | CMPC(NetIOMP * io[2], ThreadPool * pool, int party, BristolFormat * cf, bool * _delta = nullptr, int ssp = 40) { 46 | this->party = party; 47 | this->io = io[0]; 48 | this->cf = cf; 49 | this->ssp = ssp; 50 | this->pool = pool; 51 | 52 | for(int i = 0; i < cf->num_gate; ++i) { 53 | if (cf->gates[4*i+3] == AND_GATE) 54 | ++num_ands; 55 | } 56 | num_in = cf->n1+cf->n2; 57 | total_pre = num_in + num_ands + 3*ssp; 58 | fpre = new FpreMP(io, pool, party, _delta, ssp); 59 | Delta = fpre->Delta; 60 | 61 | if(party == 1) { 62 | GTM = new block[num_ands][4][nP+1]; 63 | GTK = new block[num_ands][4][nP+1]; 64 | GTv = new bool[num_ands][4]; 65 | GT = new block[num_ands][nP+1][4][nP+1]; 66 | } 67 | 68 | labels = new block[cf->num_wire]; 69 | for(int i = 1; i <= nP; ++i) { 70 | key[i] = new block[cf->num_wire]; 71 | mac[i] = new block[cf->num_wire]; 72 | ANDS_key[i] = new block[num_ands*3]; 73 | ANDS_mac[i] = new block[num_ands*3]; 74 | preprocess_mac[i] = new block[total_pre]; 75 | preprocess_key[i] = new block[total_pre]; 76 | sigma_mac[i] = new block[num_ands]; 77 | sigma_key[i] = new block[num_ands]; 78 | eval_labels[i] = new block[cf->num_wire]; 79 | } 80 | value = new bool[cf->num_wire]; 81 | ANDS_value = new bool[num_ands*3]; 82 | preprocess_value = new bool[total_pre]; 83 | sigma_value = new bool[num_ands]; 84 | } 85 | ~CMPC() { 86 | delete fpre; 87 | if(party == 1) { 88 | delete[] GTM; 89 | delete[] GTK; 90 | delete[] GTv; 91 | delete[] GT; 92 | } 93 | delete[] labels; 94 | for(int i = 1; i <= nP; ++i) { 95 | delete[] key[i]; 96 | delete[] mac[i]; 97 | delete[] ANDS_key[i]; 98 | delete[] ANDS_mac[i]; 99 | delete[] preprocess_mac[i]; 100 | delete[] preprocess_key[i]; 101 | delete[] sigma_mac[i]; 102 | delete[] sigma_key[i]; 103 | delete[] eval_labels[i]; 104 | } 105 | delete[] value; 106 | delete[] ANDS_value; 107 | delete[] preprocess_value; 108 | delete[] sigma_value; 109 | } 110 | PRG prg; 111 | 112 | void function_independent() { 113 | if(party != 1) 114 | prg.random_block(labels, cf->num_wire); 115 | 116 | fpre->compute(ANDS_mac, ANDS_key, ANDS_value, num_ands); 117 | 118 | prg.random_bool(preprocess_value, total_pre); 119 | fpre->abit->compute(preprocess_mac, preprocess_key, preprocess_value, total_pre); 120 | auto ret = fpre->abit->check(preprocess_mac, preprocess_key, preprocess_value, total_pre); 121 | ret.get(); 122 | 123 | for(int i = 1; i <= nP; ++i) { 124 | memcpy(key[i], preprocess_key[i], num_in * sizeof(block)); 125 | memcpy(mac[i], preprocess_mac[i], num_in * sizeof(block)); 126 | } 127 | memcpy(value, preprocess_value, num_in * sizeof(bool)); 128 | #ifdef __debug 129 | check_MAC(io, ANDS_mac, ANDS_key, ANDS_value, Delta, num_ands*3, party); 130 | check_correctness(io, ANDS_value, num_ands, party); 131 | #endif 132 | // ret.get(); 133 | } 134 | 135 | void function_dependent() { 136 | int ands = num_in; 137 | bool * x[nP+1]; 138 | bool * y[nP+1]; 139 | for(int i = 1; i <= nP; ++i) { 140 | x[i] = new bool[num_ands]; 141 | y[i] = new bool[num_ands]; 142 | } 143 | 144 | for(int i = 0; i < cf->num_gate; ++i) { 145 | if (cf->gates[4*i+3] == AND_GATE) { 146 | for(int j = 1; j <= nP; ++j) { 147 | key[j][cf->gates[4*i+2]] = preprocess_key[j][ands]; 148 | mac[j][cf->gates[4*i+2]] = preprocess_mac[j][ands]; 149 | } 150 | value[cf->gates[4*i+2]] = preprocess_value[ands]; 151 | ++ands; 152 | } 153 | } 154 | 155 | for(int i = 0; i < cf->num_gate; ++i) { 156 | if (cf->gates[4*i+3] == XOR_GATE) { 157 | for(int j = 1; j <= nP; ++j) { 158 | key[j][cf->gates[4*i+2]] = key[j][cf->gates[4*i]] ^ key[j][cf->gates[4*i+1]]; 159 | mac[j][cf->gates[4*i+2]] = mac[j][cf->gates[4*i]] ^ mac[j][cf->gates[4*i+1]]; 160 | } 161 | value[cf->gates[4*i+2]] = value[cf->gates[4*i]] != value[cf->gates[4*i+1]]; 162 | if(party != 1) 163 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]] ^ labels[cf->gates[4*i+1]]; 164 | } else if (cf->gates[4*i+3] == NOT_GATE) { 165 | for(int j = 1; j <= nP; ++j) { 166 | key[j][cf->gates[4*i+2]] = key[j][cf->gates[4*i]]; 167 | mac[j][cf->gates[4*i+2]] = mac[j][cf->gates[4*i]]; 168 | } 169 | value[cf->gates[4*i+2]] = value[cf->gates[4*i]]; 170 | if(party != 1) 171 | labels[cf->gates[4*i+2]] = labels[cf->gates[4*i]] ^ Delta; 172 | } 173 | } 174 | 175 | #ifdef __debug 176 | check_MAC(io, mac, key, value, Delta, cf->num_wire, party); 177 | #endif 178 | 179 | ands = 0; 180 | for(int i = 0; i < cf->num_gate; ++i) { 181 | if (cf->gates[4*i+3] == AND_GATE) { 182 | x[party][ands] = value[cf->gates[4*i]] != ANDS_value[3*ands]; 183 | y[party][ands] = value[cf->gates[4*i+1]] != ANDS_value[3*ands+1]; 184 | ands++; 185 | } 186 | } 187 | 188 | vector> res; 189 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if( (i < j) and (i == party or j == party) ) { 190 | int party2 = i + j - party; 191 | res.push_back(pool->enqueue([this, x, y, party2]() { 192 | io->send_data(party2, x[party], num_ands); 193 | io->send_data(party2, y[party], num_ands); 194 | io->flush(party2); 195 | })); 196 | res.push_back(pool->enqueue([this, x, y, party2]() { 197 | io->recv_data(party2, x[party2], num_ands); 198 | io->recv_data(party2, y[party2], num_ands); 199 | })); 200 | } 201 | joinNclean(res); 202 | for(int i = 2; i <= nP; ++i) for(int j = 0; j < num_ands; ++j) { 203 | x[1][j] = x[1][j] != x[i][j]; 204 | y[1][j] = y[1][j] != y[i][j]; 205 | } 206 | 207 | ands = 0; 208 | for(int i = 0; i < cf->num_gate; ++i) { 209 | if (cf->gates[4*i+3] == AND_GATE) { 210 | for(int j = 1; j <= nP; ++j) { 211 | sigma_mac[j][ands] = ANDS_mac[j][3*ands+2]; 212 | sigma_key[j][ands] = ANDS_key[j][3*ands+2]; 213 | } 214 | sigma_value[ands] = ANDS_value[3*ands+2]; 215 | 216 | if(x[1][ands]) { 217 | for(int j = 1; j <= nP; ++j) { 218 | sigma_mac[j][ands] = sigma_mac[j][ands] ^ ANDS_mac[j][3*ands+1]; 219 | sigma_key[j][ands] = sigma_key[j][ands] ^ ANDS_key[j][3*ands+1]; 220 | } 221 | sigma_value[ands] = sigma_value[ands] != ANDS_value[3*ands+1]; 222 | } 223 | if(y[1][ands]) { 224 | for(int j = 1; j <= nP; ++j) { 225 | sigma_mac[j][ands] = sigma_mac[j][ands] ^ ANDS_mac[j][3*ands]; 226 | sigma_key[j][ands] = sigma_key[j][ands] ^ ANDS_key[j][3*ands]; 227 | } 228 | sigma_value[ands] = sigma_value[ands] != ANDS_value[3*ands]; 229 | } 230 | if(x[1][ands] and y[1][ands]) { 231 | if(party != 1) 232 | sigma_key[1][ands] = sigma_key[1][ands] ^ Delta; 233 | else 234 | sigma_value[ands] = not sigma_value[ands]; 235 | } 236 | ands++; 237 | } 238 | }//sigma_[] stores the and of input wires to each AND gates 239 | #ifdef __debug_ 240 | check_MAC(io, sigma_mac, sigma_key, sigma_value, Delta, num_ands, party); 241 | ands = 0; 242 | for(int i = 0; i < cf->num_gate; ++i) { 243 | if (cf->gates[4*i+3] == AND_GATE) { 244 | bool tmp[] = { value[cf->gates[4*i]], value[cf->gates[4*i+1]], sigma_value[ands]}; 245 | check_correctness(io, tmp, 1, party); 246 | ands++; 247 | } 248 | } 249 | #endif 250 | 251 | ands = 0; 252 | block H[4][nP+1]; 253 | block K[4][nP+1], M[4][nP+1]; 254 | bool r[4]; 255 | if(party != 1) { 256 | for(int i = 0; i < cf->num_gate; ++i) if(cf->gates[4*i+3] == AND_GATE) { 257 | r[0] = sigma_value[ands] != value[cf->gates[4*i+2]]; 258 | r[1] = r[0] != value[cf->gates[4*i]]; 259 | r[2] = r[0] != value[cf->gates[4*i+1]]; 260 | r[3] = r[1] != value[cf->gates[4*i+1]]; 261 | 262 | for(int j = 1; j <= nP; ++j) { 263 | M[0][j] = sigma_mac[j][ands] ^ mac[j][cf->gates[4*i+2]]; 264 | M[1][j] = M[0][j] ^ mac[j][cf->gates[4*i]]; 265 | M[2][j] = M[0][j] ^ mac[j][cf->gates[4*i+1]]; 266 | M[3][j] = M[1][j] ^ mac[j][cf->gates[4*i+1]]; 267 | 268 | K[0][j] = sigma_key[j][ands] ^ key[j][cf->gates[4*i+2]]; 269 | K[1][j] = K[0][j] ^ key[j][cf->gates[4*i]]; 270 | K[2][j] = K[0][j] ^ key[j][cf->gates[4*i+1]]; 271 | K[3][j] = K[1][j] ^ key[j][cf->gates[4*i+1]]; 272 | } 273 | K[3][1] = K[3][1] ^ Delta; 274 | 275 | Hash(H, labels[cf->gates[4*i]], labels[cf->gates[4*i+1]], ands); 276 | for(int j = 0; j < 4; ++j) { 277 | for(int k = 1; k <= nP; ++k) if(k != party) { 278 | H[j][k] = H[j][k] ^ M[j][k]; 279 | H[j][party] = H[j][party] ^ K[j][k]; 280 | } 281 | H[j][party] = H[j][party] ^ labels[cf->gates[4*i+2]]; 282 | if(r[j]) 283 | H[j][party] = H[j][party] ^ Delta; 284 | } 285 | for(int j = 0; j < 4; ++j) 286 | io->send_data(1, H[j]+1, sizeof(block)*(nP)); 287 | ++ands; 288 | } 289 | io->flush(1); 290 | } else { 291 | for(int i = 2; i <= nP; ++i) { 292 | int party2 = i; 293 | res.push_back(pool->enqueue([this, party2]() { 294 | for(int i = 0; i < num_ands; ++i) 295 | for(int j = 0; j < 4; ++j) 296 | io->recv_data(party2, GT[i][party2][j]+1, sizeof(block)*(nP)); 297 | })); 298 | } 299 | for(int i = 0; i < cf->num_gate; ++i) if(cf->gates[4*i+3] == AND_GATE) { 300 | r[0] = sigma_value[ands] != value[cf->gates[4*i+2]]; 301 | r[1] = r[0] != value[cf->gates[4*i]]; 302 | r[2] = r[0] != value[cf->gates[4*i+1]]; 303 | r[3] = r[1] != value[cf->gates[4*i+1]]; 304 | r[3] = r[3] != true; 305 | 306 | for(int j = 1; j <= nP; ++j) { 307 | M[0][j] = sigma_mac[j][ands] ^ mac[j][cf->gates[4*i+2]]; 308 | M[1][j] = M[0][j] ^ mac[j][cf->gates[4*i]]; 309 | M[2][j] = M[0][j] ^ mac[j][cf->gates[4*i+1]]; 310 | M[3][j] = M[1][j] ^ mac[j][cf->gates[4*i+1]]; 311 | 312 | K[0][j] = sigma_key[j][ands] ^ key[j][cf->gates[4*i+2]]; 313 | K[1][j] = K[0][j] ^ key[j][cf->gates[4*i]]; 314 | K[2][j] = K[0][j] ^ key[j][cf->gates[4*i+1]]; 315 | K[3][j] = K[1][j] ^ key[j][cf->gates[4*i+1]]; 316 | } 317 | memcpy(GTK[ands], K, sizeof(block)*4*(nP+1)); 318 | memcpy(GTM[ands], M, sizeof(block)*4*(nP+1)); 319 | memcpy(GTv[ands], r, sizeof(bool)*4); 320 | ++ands; 321 | } 322 | joinNclean(res); 323 | } 324 | for(int i = 1; i <= nP; ++i) { 325 | delete[] x[i]; 326 | delete[] y[i]; 327 | } 328 | } 329 | 330 | void online (bool * input, bool * output) { 331 | bool * mask_input = new bool[cf->num_wire]; 332 | for(int i = 0; i < num_in; ++i) 333 | mask_input[i] = input[i] != value[i]; 334 | if(party != 1) { 335 | io->send_data(1, mask_input, num_in); 336 | io->flush(1); 337 | io->recv_data(1, mask_input, num_in); 338 | } else { 339 | bool * tmp[nP+1]; 340 | for(int i = 2; i <= nP; ++i) tmp[i] = new bool[num_in]; 341 | vector> res; 342 | for(int i = 2; i <= nP; ++i) { 343 | int party2 = i; 344 | res.push_back(pool->enqueue([this, tmp, party2]() { 345 | io->recv_data(party2, tmp[party2], num_in); 346 | })); 347 | } 348 | joinNclean(res); 349 | for(int i = 0; i < num_in; ++i) 350 | for(int j = 2; j <= nP; ++j) 351 | mask_input[i] = tmp[j][i] != mask_input[i]; 352 | for(int i = 2; i <= nP; ++i) { 353 | int party2 = i; 354 | res.push_back(pool->enqueue([this, mask_input, party2]() { 355 | io->send_data(party2, mask_input, num_in); 356 | io->flush(party2); 357 | })); 358 | } 359 | joinNclean(res); 360 | for(int i = 2; i <= nP; ++i) delete[] tmp[i]; 361 | } 362 | 363 | if(party!= 1) { 364 | for(int i = 0; i < num_in; ++i) { 365 | block tmp = labels[i]; 366 | if(mask_input[i]) tmp = tmp ^ Delta; 367 | io->send_data(1, &tmp, sizeof(block)); 368 | } 369 | io->flush(1); 370 | } else { 371 | vector> res; 372 | for(int i = 2; i <= nP; ++i) { 373 | int party2 = i; 374 | res.push_back(pool->enqueue([this, party2]() { 375 | io->recv_data(party2, eval_labels[party2], num_in*sizeof(block)); 376 | })); 377 | } 378 | joinNclean(res); 379 | 380 | int ands = 0; 381 | for(int i = 0; i < cf->num_gate; ++i) { 382 | if (cf->gates[4*i+3] == XOR_GATE) { 383 | for(int j = 2; j<= nP; ++j) 384 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]] ^ eval_labels[j][cf->gates[4*i+1]]; 385 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i]] != mask_input[cf->gates[4*i+1]]; 386 | } else if (cf->gates[4*i+3] == AND_GATE) { 387 | int index = 2*mask_input[cf->gates[4*i]] + mask_input[cf->gates[4*i+1]]; 388 | block H[nP+1]; 389 | for(int j = 2; j <= nP; ++j) 390 | eval_labels[j][cf->gates[4*i+2]] = GTM[ands][index][j]; 391 | mask_input[cf->gates[4*i+2]] = GTv[ands][index]; 392 | for(int j = 2; j <= nP; ++j) { 393 | Hash(H, eval_labels[j][cf->gates[4*i]], eval_labels[j][cf->gates[4*i+1]], ands, index); 394 | xorBlocks_arr(H, H, GT[ands][j][index], nP+1); 395 | for(int k = 2; k <= nP; ++k) 396 | eval_labels[k][cf->gates[4*i+2]] = H[k] ^ eval_labels[k][cf->gates[4*i+2]]; 397 | 398 | block t0 = GTK[ands][index][j] ^ Delta; 399 | 400 | if(cmpBlock(&H[1], >K[ands][index][j], 1)) 401 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != false; 402 | else if(cmpBlock(&H[1], &t0, 1)) 403 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != true; 404 | else {cout <gates[4*i+2]] = not mask_input[cf->gates[4*i]]; 410 | for(int j = 2; j <= nP; ++j) 411 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]]; 412 | } 413 | } 414 | } 415 | if(party != 1) { 416 | io->send_data(1, value+cf->num_wire - cf->n3, cf->n3); 417 | io->flush(1); 418 | } else { 419 | vector> res; 420 | bool * tmp[nP+1]; 421 | for(int i = 2; i <= nP; ++i) 422 | tmp[i] = new bool[cf->n3]; 423 | for(int i = 2; i <= nP; ++i) { 424 | int party2 = i; 425 | res.push_back(pool->enqueue([this, tmp, party2]() { 426 | io->recv_data(party2, tmp[party2], cf->n3); 427 | })); 428 | } 429 | joinNclean(res); 430 | for(int i = 0; i < cf->n3; ++i) 431 | for(int j = 2; j <= nP; ++j) 432 | mask_input[cf->num_wire - cf->n3 + i] = tmp[j][i] != mask_input[cf->num_wire - cf->n3 + i]; 433 | for(int i = 0; i < cf->n3; ++i) 434 | mask_input[cf->num_wire - cf->n3 + i] = value[cf->num_wire - cf->n3 + i] != mask_input[cf->num_wire - cf->n3 + i]; 435 | 436 | for(int i = 2; i <= nP; ++i) delete[] tmp[i]; 437 | memcpy(output, mask_input + cf->num_wire - cf->n3, cf->n3); 438 | } 439 | delete[] mask_input; 440 | } 441 | void Hash(block H[4][nP+1], const block & a, const block & b, uint64_t idx) { 442 | block T[4]; 443 | T[0] = sigma(a); 444 | T[1] = sigma(a ^ Delta); 445 | T[2] = sigma(sigma(b)); 446 | T[3] = sigma(sigma(b ^ Delta)); 447 | 448 | H[0][0] = T[0] ^ T[2]; 449 | H[1][0] = T[0] ^ T[3]; 450 | H[2][0] = T[1] ^ T[2]; 451 | H[3][0] = T[1] ^ T[3]; 452 | for(int j = 0; j < 4; ++j) for(int i = 1; i <= nP; ++i) { 453 | H[j][i] = H[j][0] ^ makeBlock(4*idx+j, i); 454 | } 455 | for(int j = 0; j < 4; ++j) { 456 | prp.permute_block(H[j]+1, nP); 457 | } 458 | } 459 | 460 | void Hash(block H[nP+1], const block &a, const block& b, uint64_t idx, uint64_t row) { 461 | H[0] = sigma(a) ^ sigma(sigma(b)); 462 | for(int i = 1; i <= nP; ++i) { 463 | H[i] = H[0] ^ makeBlock(4*idx+row, i); 464 | } 465 | prp.permute_block(H+1, nP); 466 | } 467 | 468 | string tostring(bool a) { 469 | if(a) return "T"; 470 | else return "F"; 471 | } 472 | 473 | void online (bool * input, bool * output, int* start, int* end) { 474 | bool * mask_input = new bool[cf->num_wire]; 475 | bool * input_mask[nP+1]; 476 | for(int i = 0; i <= nP; ++i) input_mask[i] = new bool[end[party] - start[party]]; 477 | memcpy(input_mask[party], value+start[party], end[party] - start[party]); 478 | memcpy(input_mask[0], input+start[party], end[party] - start[party]); 479 | 480 | vector> res; 481 | for(int i = 1; i <= nP; ++i) for(int j = 1; j<= nP; ++j) if( (i < j) and (i == party or j == party) ) { 482 | int party2 = i + j - party; 483 | res.push_back(pool->enqueue([this, start, end, party2]() { 484 | char dig[Hash::DIGEST_SIZE]; 485 | io->send_data(party2, value+start[party2], end[party2]-start[party2]); 486 | emp::Hash::hash_once(dig, mac[party2]+start[party2], (end[party2]-start[party2])*sizeof(block)); 487 | io->send_data(party2, dig, Hash::DIGEST_SIZE); 488 | io->flush(party2); 489 | return false; 490 | })); 491 | res.push_back(pool->enqueue([this, start, end, input_mask, party2]() { 492 | char dig[Hash::DIGEST_SIZE]; 493 | char dig2[Hash::DIGEST_SIZE]; 494 | io->recv_data(party2, input_mask[party2], end[party]-start[party]); 495 | block * tmp = new block[end[party]-start[party]]; 496 | for(int i = 0; i < end[party] - start[party]; ++i) { 497 | tmp[i] = key[party2][i+start[party]]; 498 | if(input_mask[party2][i])tmp[i] = tmp[i] ^ Delta; 499 | } 500 | emp::Hash::hash_once(dig2, tmp, (end[party]-start[party])*sizeof(block)); 501 | io->recv_data(party2, dig, Hash::DIGEST_SIZE); 502 | delete[] tmp; 503 | return strncmp(dig, dig2, Hash::DIGEST_SIZE) != 0; 504 | })); 505 | } 506 | if(joinNcleanCheat(res)) error("cheat!"); 507 | for(int i = 1; i <= nP; ++i) 508 | for(int j = 0; j < end[party] - start[party]; ++j) 509 | input_mask[0][j] = input_mask[0][j] != input_mask[i][j]; 510 | 511 | 512 | if(party != 1) { 513 | io->send_data(1, input_mask[0], end[party] - start[party]); 514 | io->flush(1); 515 | io->recv_data(1, mask_input, num_in); 516 | } else { 517 | vector> res; 518 | for(int i = 2; i <= nP; ++i) { 519 | int party2 = i; 520 | res.push_back(pool->enqueue([this, mask_input, start, end , party2]() { 521 | io->recv_data(party2, mask_input+start[party2], end[party2] - start[party2]); 522 | })); 523 | } 524 | joinNclean(res); 525 | memcpy(mask_input, input_mask[0], end[1]-start[1]); 526 | for(int i = 2; i <= nP; ++i) { 527 | int party2 = i; 528 | res.push_back(pool->enqueue([this, mask_input, party2]() { 529 | io->send_data(party2, mask_input, num_in); 530 | io->flush(party2); 531 | })); 532 | } 533 | joinNclean(res); 534 | } 535 | 536 | if(party!= 1) { 537 | for(int i = 0; i < num_in; ++i) { 538 | block tmp = labels[i]; 539 | if(mask_input[i]) tmp = tmp ^ Delta; 540 | io->send_data(1, &tmp, sizeof(block)); 541 | } 542 | io->flush(1); 543 | } else { 544 | vector> res; 545 | for(int i = 2; i <= nP; ++i) { 546 | int party2 = i; 547 | res.push_back(pool->enqueue([this, party2]() { 548 | io->recv_data(party2, eval_labels[party2], num_in*sizeof(block)); 549 | })); 550 | } 551 | joinNclean(res); 552 | 553 | int ands = 0; 554 | for(int i = 0; i < cf->num_gate; ++i) { 555 | if (cf->gates[4*i+3] == XOR_GATE) { 556 | for(int j = 2; j<= nP; ++j) 557 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]] ^ eval_labels[j][cf->gates[4*i+1]]; 558 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i]] != mask_input[cf->gates[4*i+1]]; 559 | } else if (cf->gates[4*i+3] == AND_GATE) { 560 | int index = 2*mask_input[cf->gates[4*i]] + mask_input[cf->gates[4*i+1]]; 561 | block H[nP+1]; 562 | for(int j = 2; j <= nP; ++j) 563 | eval_labels[j][cf->gates[4*i+2]] = GTM[ands][index][j]; 564 | mask_input[cf->gates[4*i+2]] = GTv[ands][index]; 565 | for(int j = 2; j <= nP; ++j) { 566 | Hash(H, eval_labels[j][cf->gates[4*i]], eval_labels[j][cf->gates[4*i+1]], ands, index); 567 | xorBlocks_arr(H, H, GT[ands][j][index], nP+1); 568 | for(int k = 2; k <= nP; ++k) 569 | eval_labels[k][cf->gates[4*i+2]] = H[k] ^ eval_labels[k][cf->gates[4*i+2]]; 570 | 571 | block t0 = GTK[ands][index][j] ^ Delta; 572 | 573 | if(cmpBlock(&H[1], >K[ands][index][j], 1)) 574 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != false; 575 | else if(cmpBlock(&H[1], &t0, 1)) 576 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != true; 577 | else {cout <gates[4*i+2]] = not mask_input[cf->gates[4*i]]; 583 | for(int j = 2; j <= nP; ++j) 584 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]]; 585 | } 586 | } 587 | } 588 | if(party != 1) { 589 | io->send_data(1, value+cf->num_wire - cf->n3, cf->n3); 590 | io->flush(1); 591 | } else { 592 | vector> res; 593 | bool * tmp[nP+1]; 594 | for(int i = 2; i <= nP; ++i) 595 | tmp[i] = new bool[cf->n3]; 596 | for(int i = 2; i <= nP; ++i) { 597 | int party2 = i; 598 | res.push_back(pool->enqueue([this, tmp, party2]() { 599 | io->recv_data(party2, tmp[party2], cf->n3); 600 | })); 601 | } 602 | joinNclean(res); 603 | for(int i = 0; i < cf->n3; ++i) 604 | for(int j = 2; j <= nP; ++j) 605 | mask_input[cf->num_wire - cf->n3 + i] = tmp[j][i] != mask_input[cf->num_wire - cf->n3 + i]; 606 | for(int i = 0; i < cf->n3; ++i) 607 | mask_input[cf->num_wire - cf->n3 + i] = value[cf->num_wire - cf->n3 + i] != mask_input[cf->num_wire - cf->n3 + i]; 608 | 609 | for(int i = 2; i <= nP; ++i) delete[] tmp[i]; 610 | memcpy(output, mask_input + cf->num_wire - cf->n3, cf->n3); 611 | } 612 | delete[] mask_input; 613 | } 614 | 615 | void online (FlexIn * input, FlexOut *output) { 616 | bool * mask_input = new bool[cf->num_wire]; 617 | input->associate_cmpc(pool, value, mac, key, io, Delta); 618 | input->input(mask_input); 619 | 620 | if(party!= 1) { 621 | for(int i = 0; i < num_in; ++i) { 622 | block tmp = labels[i]; 623 | if(mask_input[i]) tmp = tmp ^ Delta; 624 | io->send_data(1, &tmp, sizeof(block)); 625 | } 626 | io->flush(1); 627 | } else { 628 | vector> res; 629 | for(int i = 2; i <= nP; ++i) { 630 | int party2 = i; 631 | res.push_back(pool->enqueue([this, party2]() { 632 | io->recv_data(party2, eval_labels[party2], num_in*sizeof(block)); 633 | })); 634 | } 635 | joinNclean(res); 636 | 637 | int ands = 0; 638 | for(int i = 0; i < cf->num_gate; ++i) { 639 | if (cf->gates[4*i+3] == XOR_GATE) { 640 | for(int j = 2; j<= nP; ++j) 641 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]] ^ eval_labels[j][cf->gates[4*i+1]]; 642 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i]] != mask_input[cf->gates[4*i+1]]; 643 | } else if (cf->gates[4*i+3] == AND_GATE) { 644 | int index = 2*mask_input[cf->gates[4*i]] + mask_input[cf->gates[4*i+1]]; 645 | block H[nP+1]; 646 | for(int j = 2; j <= nP; ++j) 647 | eval_labels[j][cf->gates[4*i+2]] = GTM[ands][index][j]; 648 | mask_input[cf->gates[4*i+2]] = GTv[ands][index]; 649 | for(int j = 2; j <= nP; ++j) { 650 | Hash(H, eval_labels[j][cf->gates[4*i]], eval_labels[j][cf->gates[4*i+1]], ands, index); 651 | xorBlocks_arr(H, H, GT[ands][j][index], nP+1); 652 | for(int k = 2; k <= nP; ++k) 653 | eval_labels[k][cf->gates[4*i+2]] = H[k] ^ eval_labels[k][cf->gates[4*i+2]]; 654 | 655 | block t0 = GTK[ands][index][j] ^ Delta; 656 | 657 | if(cmpBlock(&H[1], >K[ands][index][j], 1)) 658 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != false; 659 | else if(cmpBlock(&H[1], &t0, 1)) 660 | mask_input[cf->gates[4*i+2]] = mask_input[cf->gates[4*i+2]] != true; 661 | else {cout <gates[4*i+2]] = not mask_input[cf->gates[4*i]]; 667 | for(int j = 2; j <= nP; ++j) 668 | eval_labels[j][cf->gates[4*i+2]] = eval_labels[j][cf->gates[4*i]]; 669 | } 670 | } 671 | } 672 | 673 | output->associate_cmpc(pool, value, mac, key, eval_labels, labels, io, Delta); 674 | output->output(mask_input, cf->num_wire - cf->n3); 675 | 676 | delete[] mask_input; 677 | } 678 | }; 679 | #endif// CMPC_H__ 680 | -------------------------------------------------------------------------------- /emp-agmpc/netmp.h: -------------------------------------------------------------------------------- 1 | #ifndef NETIOMP_H__ 2 | #define NETIOMP_H__ 3 | #include 4 | #include "cmpc_config.h" 5 | using namespace emp; 6 | 7 | template 8 | class NetIOMP { public: 9 | NetIO*ios[nP+1]; 10 | NetIO*ios2[nP+1]; 11 | int party; 12 | bool sent[nP+1]; 13 | NetIOMP(int party, int port) { 14 | this->party = party; 15 | memset(sent, false, nP+1); 16 | for(int i = 1; i <= nP; ++i)for(int j = 1; j <= nP; ++j)if(i < j){ 17 | if(i == party) { 18 | #ifdef LOCALHOST 19 | usleep(1000); 20 | ios[j] = new NetIO(IP[j], port+2*(i*nP+j), true); 21 | #else 22 | usleep(1000); 23 | ios[j] = new NetIO(IP[j], port+2*(i), true); 24 | #endif 25 | ios[j]->set_nodelay(); 26 | 27 | #ifdef LOCALHOST 28 | usleep(1000); 29 | ios2[j] = new NetIO(nullptr, port+2*(i*nP+j)+1, true); 30 | #else 31 | usleep(1000); 32 | ios2[j] = new NetIO(nullptr, port+2*(j)+1, true); 33 | #endif 34 | ios2[j]->set_nodelay(); 35 | } else if(j == party) { 36 | #ifdef LOCALHOST 37 | usleep(1000); 38 | ios[i] = new NetIO(nullptr, port+2*(i*nP+j), true); 39 | #else 40 | usleep(1000); 41 | ios[i] = new NetIO(nullptr, port+2*(i), true); 42 | #endif 43 | ios[i]->set_nodelay(); 44 | 45 | #ifdef LOCALHOST 46 | usleep(1000); 47 | ios2[i] = new NetIO(IP[i], port+2*(i*nP+j)+1, true); 48 | #else 49 | usleep(1000); 50 | ios2[i] = new NetIO(IP[i], port+2*(j)+1, true); 51 | #endif 52 | ios2[i]->set_nodelay(); 53 | } 54 | } 55 | } 56 | int64_t count() { 57 | int64_t res = 0; 58 | for(int i = 1; i <= nP; ++i) if(i != party){ 59 | res += ios[i]->counter; 60 | res += ios2[i]->counter; 61 | } 62 | return res; 63 | } 64 | 65 | ~NetIOMP() { 66 | for(int i = 1; i <= nP; ++i) 67 | if(i != party) { 68 | delete ios[i]; 69 | delete ios2[i]; 70 | } 71 | } 72 | void send_data(int dst, const void * data, size_t len) { 73 | if(dst != 0 and dst!= party) { 74 | if(party < dst) 75 | ios[dst]->send_data(data, len); 76 | else 77 | ios2[dst]->send_data(data, len); 78 | sent[dst] = true; 79 | } 80 | #ifdef __MORE_FLUSH 81 | flush(dst); 82 | #endif 83 | } 84 | void recv_data(int src, void * data, size_t len) { 85 | if(src != 0 and src!= party) { 86 | if(sent[src])flush(src); 87 | if(src < party) 88 | ios[src]->recv_data(data, len); 89 | else 90 | ios2[src]->recv_data(data, len); 91 | } 92 | } 93 | NetIO*& get(size_t idx, bool b = false){ 94 | if (b) 95 | return ios[idx]; 96 | else return ios2[idx]; 97 | } 98 | void flush(int idx = 0) { 99 | if(idx == 0) { 100 | for(int i = 1; i <= nP; ++i) 101 | if(i != party) { 102 | ios[i]->flush(); 103 | ios2[i]->flush(); 104 | } 105 | } else { 106 | if(party < idx) 107 | ios[idx]->flush(); 108 | else 109 | ios2[idx]->flush(); 110 | } 111 | } 112 | void sync() { 113 | for(int i = 1; i <= nP; ++i) for(int j = 1; j <= nP; ++j) if(i < j) { 114 | if(i == party) { 115 | ios[j]->sync(); 116 | ios2[j]->sync(); 117 | } else if(j == party) { 118 | ios[i]->sync(); 119 | ios2[i]->sync(); 120 | } 121 | } 122 | } 123 | }; 124 | #endif //NETIOMP_H__ 125 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | $1 1 12345 & $1 2 12345 & $1 3 12345 3 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Testing macro 2 | macro (add_test_executable_with_lib _name libs) 3 | add_executable(test_${_name} "${_name}.cpp") 4 | target_link_libraries(test_${_name} ${EMP-OT_LIBRARIES}) 5 | endmacro() 6 | 7 | macro (add_test_case _name) 8 | add_test_executable_with_lib(${_name} "") 9 | add_test(NAME ${_name} COMMAND "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_${_name}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/") 10 | endmacro() 11 | 12 | macro (add_test_case_with_run _name) 13 | add_test_executable_with_lib(${_name} "") 14 | add_test(NAME ${_name} COMMAND "./run" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_${_name}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/") 15 | 16 | endmacro() 17 | 18 | # Test cases 19 | add_test_case_with_run(test_mpc) 20 | add_test_case_with_run(test_mpc_individual) 21 | add_test_case_with_run(aes) 22 | add_test_case_with_run(sha1) 23 | add_test_case_with_run(sha256) 24 | add_test_case_with_run(triple) 25 | add_test_case_with_run(pr10_test) 26 | add_test_case_with_run(test_in_out) 27 | -------------------------------------------------------------------------------- /test/aes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emp-agmpc/emp-agmpc.h" 3 | #include "test/test.h" 4 | using namespace std; 5 | using namespace emp; 6 | 7 | const static int nP = 3; 8 | int party, port; 9 | int main(int argc, char** argv) { 10 | parse_party_and_port(argv, &party, &port); 11 | if(party > nP)return 0; 12 | NetIOMP io(party, port); 13 | #ifdef LOCALHOST 14 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 15 | #else 16 | NetIOMP io2(party, port+2*(nP+1)); 17 | #endif 18 | NetIOMP *ios[2] = {&io, &io2}; 19 | ThreadPool pool(2*(nP-1)+2); 20 | 21 | bench_once(party, ios, &pool, circuit_file_location+"AES-non-expanded.txt"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/not.txt: -------------------------------------------------------------------------------- 1 | 8 16 2 | 4 4 8 3 | 4 | 1 1 0 8 INV 5 | 1 1 1 9 INV 6 | 1 1 2 10 INV 7 | 1 1 3 11 INV 8 | 1 1 4 12 INV 9 | 1 1 5 13 INV 10 | 1 1 6 14 INV 11 | 1 1 7 15 INV 12 | -------------------------------------------------------------------------------- /test/pr10_circuit.txt: -------------------------------------------------------------------------------- 1 | 158 222 2 | 32 32 1 3 | 4 | 2 1 32 0 64 XOR 5 | 2 1 64 0 65 AND 6 | 2 1 33 1 66 XOR 7 | 2 1 65 1 67 XOR 8 | 2 1 66 65 68 XOR 9 | 2 1 66 67 69 AND 10 | 2 1 65 69 70 XOR 11 | 2 1 34 2 71 XOR 12 | 2 1 70 2 72 XOR 13 | 2 1 71 70 73 XOR 14 | 2 1 71 72 74 AND 15 | 2 1 70 74 75 XOR 16 | 2 1 35 3 76 XOR 17 | 2 1 75 3 77 XOR 18 | 2 1 76 75 78 XOR 19 | 2 1 76 77 79 AND 20 | 2 1 75 79 80 XOR 21 | 2 1 36 4 81 XOR 22 | 2 1 80 4 82 XOR 23 | 2 1 81 80 83 XOR 24 | 2 1 81 82 84 AND 25 | 2 1 80 84 85 XOR 26 | 2 1 37 5 86 XOR 27 | 2 1 85 5 87 XOR 28 | 2 1 86 85 88 XOR 29 | 2 1 86 87 89 AND 30 | 2 1 85 89 90 XOR 31 | 2 1 38 6 91 XOR 32 | 2 1 90 6 92 XOR 33 | 2 1 91 90 93 XOR 34 | 2 1 91 92 94 AND 35 | 2 1 90 94 95 XOR 36 | 2 1 39 7 96 XOR 37 | 2 1 95 7 97 XOR 38 | 2 1 96 95 98 XOR 39 | 2 1 96 97 99 AND 40 | 2 1 95 99 100 XOR 41 | 2 1 40 8 101 XOR 42 | 2 1 100 8 102 XOR 43 | 2 1 101 100 103 XOR 44 | 2 1 101 102 104 AND 45 | 2 1 100 104 105 XOR 46 | 2 1 41 9 106 XOR 47 | 2 1 105 9 107 XOR 48 | 2 1 106 105 108 XOR 49 | 2 1 106 107 109 AND 50 | 2 1 105 109 110 XOR 51 | 2 1 42 10 111 XOR 52 | 2 1 110 10 112 XOR 53 | 2 1 111 110 113 XOR 54 | 2 1 111 112 114 AND 55 | 2 1 110 114 115 XOR 56 | 2 1 43 11 116 XOR 57 | 2 1 115 11 117 XOR 58 | 2 1 116 115 118 XOR 59 | 2 1 116 117 119 AND 60 | 2 1 115 119 120 XOR 61 | 2 1 44 12 121 XOR 62 | 2 1 120 12 122 XOR 63 | 2 1 121 120 123 XOR 64 | 2 1 121 122 124 AND 65 | 2 1 120 124 125 XOR 66 | 2 1 45 13 126 XOR 67 | 2 1 125 13 127 XOR 68 | 2 1 126 125 128 XOR 69 | 2 1 126 127 129 AND 70 | 2 1 125 129 130 XOR 71 | 2 1 46 14 131 XOR 72 | 2 1 130 14 132 XOR 73 | 2 1 131 130 133 XOR 74 | 2 1 131 132 134 AND 75 | 2 1 130 134 135 XOR 76 | 2 1 47 15 136 XOR 77 | 2 1 135 15 137 XOR 78 | 2 1 136 135 138 XOR 79 | 2 1 136 137 139 AND 80 | 2 1 135 139 140 XOR 81 | 2 1 48 16 141 XOR 82 | 2 1 140 16 142 XOR 83 | 2 1 141 140 143 XOR 84 | 2 1 141 142 144 AND 85 | 2 1 140 144 145 XOR 86 | 2 1 49 17 146 XOR 87 | 2 1 145 17 147 XOR 88 | 2 1 146 145 148 XOR 89 | 2 1 146 147 149 AND 90 | 2 1 145 149 150 XOR 91 | 2 1 50 18 151 XOR 92 | 2 1 150 18 152 XOR 93 | 2 1 151 150 153 XOR 94 | 2 1 151 152 154 AND 95 | 2 1 150 154 155 XOR 96 | 2 1 51 19 156 XOR 97 | 2 1 155 19 157 XOR 98 | 2 1 156 155 158 XOR 99 | 2 1 156 157 159 AND 100 | 2 1 155 159 160 XOR 101 | 2 1 52 20 161 XOR 102 | 2 1 160 20 162 XOR 103 | 2 1 161 160 163 XOR 104 | 2 1 161 162 164 AND 105 | 2 1 160 164 165 XOR 106 | 2 1 53 21 166 XOR 107 | 2 1 165 21 167 XOR 108 | 2 1 166 165 168 XOR 109 | 2 1 166 167 169 AND 110 | 2 1 165 169 170 XOR 111 | 2 1 54 22 171 XOR 112 | 2 1 170 22 172 XOR 113 | 2 1 171 170 173 XOR 114 | 2 1 171 172 174 AND 115 | 2 1 170 174 175 XOR 116 | 2 1 55 23 176 XOR 117 | 2 1 175 23 177 XOR 118 | 2 1 176 175 178 XOR 119 | 2 1 176 177 179 AND 120 | 2 1 175 179 180 XOR 121 | 2 1 56 24 181 XOR 122 | 2 1 180 24 182 XOR 123 | 2 1 181 180 183 XOR 124 | 2 1 181 182 184 AND 125 | 2 1 180 184 185 XOR 126 | 2 1 57 25 186 XOR 127 | 2 1 185 25 187 XOR 128 | 2 1 186 185 188 XOR 129 | 2 1 186 187 189 AND 130 | 2 1 185 189 190 XOR 131 | 2 1 58 26 191 XOR 132 | 2 1 190 26 192 XOR 133 | 2 1 191 190 193 XOR 134 | 2 1 191 192 194 AND 135 | 2 1 190 194 195 XOR 136 | 2 1 59 27 196 XOR 137 | 2 1 195 27 197 XOR 138 | 2 1 196 195 198 XOR 139 | 2 1 196 197 199 AND 140 | 2 1 195 199 200 XOR 141 | 2 1 60 28 201 XOR 142 | 2 1 200 28 202 XOR 143 | 2 1 201 200 203 XOR 144 | 2 1 201 202 204 AND 145 | 2 1 200 204 205 XOR 146 | 2 1 61 29 206 XOR 147 | 2 1 205 29 207 XOR 148 | 2 1 206 205 208 XOR 149 | 2 1 206 207 209 AND 150 | 2 1 205 209 210 XOR 151 | 2 1 62 30 211 XOR 152 | 2 1 210 30 212 XOR 153 | 2 1 211 210 213 XOR 154 | 2 1 211 212 214 AND 155 | 2 1 210 214 215 XOR 156 | 2 1 63 31 216 XOR 157 | 2 1 216 215 217 XOR 158 | 1 1 217 218 INV 159 | 1 1 218 219 INV 160 | 2 1 0 0 220 XOR 161 | 2 1 220 219 221 XOR 162 | -------------------------------------------------------------------------------- /test/pr10_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emp-agmpc/emp-agmpc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | //const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH); 7 | 8 | // test from root directory of repo using 9 | // ./run ./bin/pr10_test ... 10 | 11 | const static int nP = 3; 12 | int party, port; 13 | void bench_once(NetIOMP * ios[2], ThreadPool * pool, string filename) { 14 | if(party == 1)cout <<"CIRCUIT:\t"<* mpc = new CMPC(ios, pool, party, &cf); 20 | ios[0]->flush(); 21 | ios[1]->flush(); 22 | double t2 = time_from(start); 23 | // ios[0]->sync(); 24 | // ios[1]->sync(); 25 | if(party == 1)cout <<"Setup:\t"<function_independent(); 29 | ios[0]->flush(); 30 | ios[1]->flush(); 31 | t2 = time_from(start); 32 | if(party == 1)cout <<"FUNC_IND:\t"<function_dependent(); 36 | ios[0]->flush(); 37 | ios[1]->flush(); 38 | t2 = time_from(start); 39 | if(party == 1)cout <<"FUNC_DEP:\t"<online(in, out); 45 | ios[0]->flush(); 46 | ios[1]->flush(); 47 | t2 = time_from(start); 48 | // uint64_t band2 = io.count(); 49 | // if(party == 1)cout <<"bandwidth\t"< nP)return 0; 56 | NetIOMP io(party, port); 57 | #ifdef LOCALHOST 58 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 59 | #else 60 | NetIOMP io2(party, port+2*(nP+1)); 61 | #endif 62 | NetIOMP *ios[2] = {&io, &io2}; 63 | ThreadPool pool(2*(nP-1)+2); 64 | 65 | char d[100]; 66 | char* t = getcwd(d, 100); 67 | (void) t; 68 | string circuit_file_location = string(d) + "/test/"; 69 | bench_once(ios, &pool, circuit_file_location+"pr10_circuit.txt"); 70 | return 0; 71 | } -------------------------------------------------------------------------------- /test/scratch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "netmp.h" 3 | #include "abitmp.h" 4 | #include "fpremp.h" 5 | using namespace std; 6 | 7 | int main(int argc, char** argv) { 8 | int port, party; 9 | parse_party_and_port(argv, &party, &port); 10 | 11 | NetIOMP<3> io(party, port); 12 | for(int i = 1; i <= 3; ++i)for(int j = 1; j <= 3; ++j)if(i < j) { 13 | if(i == party) { 14 | int data = i*100+j; 15 | io.send_data(j, &data, 4); 16 | } else if (j == party) { 17 | int data = 0; 18 | io.recv_data(i, &data, 4); 19 | if(data!= i*100+j) { 20 | cout <<"WRONG\n"< abitmp(&io, &pool, party); 39 | double t1 = timeStamp(); 40 | abitmp.compute(MAC, KEY, data, LEN); 41 | if(party == 1) 42 | cout < fpre(&io, &pool, party); 53 | // fpre.compute(MAC, KEY, data, LEN); 54 | 55 | // cout <<"DONE3 !"< 2 | #include "emp-agmpc/emp-agmpc.h" 3 | #include "test/test.h" 4 | using namespace std; 5 | using namespace emp; 6 | 7 | const static int nP = 3; 8 | int party, port; 9 | int main(int argc, char** argv) { 10 | parse_party_and_port(argv, &party, &port); 11 | if(party > nP)return 0; 12 | NetIOMP io(party, port); 13 | #ifdef LOCALHOST 14 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 15 | #else 16 | NetIOMP io2(party, port+2*(nP+1)); 17 | #endif 18 | NetIOMP *ios[2] = {&io, &io2}; 19 | ThreadPool pool(2*(nP-1)+2); 20 | 21 | bench_once(party, ios, &pool, circuit_file_location+"sha-1.txt"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/sha256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emp-agmpc/emp-agmpc.h" 3 | #include "test/test.h" 4 | using namespace std; 5 | using namespace emp; 6 | 7 | const static int nP = 3; 8 | int party, port; 9 | int main(int argc, char** argv) { 10 | parse_party_and_port(argv, &party, &port); 11 | if(party > nP)return 0; 12 | NetIOMP io(party, port); 13 | #ifdef LOCALHOST 14 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 15 | #else 16 | NetIOMP io2(party, port+2*(nP+1)); 17 | #endif 18 | NetIOMP *ios[2] = {&io, &io2}; 19 | ThreadPool pool(2*(nP-1)+2); 20 | 21 | bench_once(party, ios, &pool, circuit_file_location+"sha-256.txt"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef EMP_AGMPC_TEST_H__ 2 | #define EMP_AGMPC_TEST_H__ 3 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH) + string("bristol_format/"); 4 | 5 | 6 | template 7 | int communication(NetIOMP * ios[2]) { 8 | return ios[0]->count() + ios[1]->count(); 9 | } 10 | 11 | template 12 | void bench_once(int party, NetIOMP * ios[2], ThreadPool * pool, string filename) { 13 | if(party == 1)cout <<"CIRCUIT:\t"<* mpc = new CMPC(ios, pool, party, &cf); 19 | ios[0]->flush(); 20 | ios[1]->flush(); 21 | double t2 = time_from(start); 22 | // ios[0]->sync(); 23 | // ios[1]->sync(); 24 | if(party == 1)cout <<"Setup:\t"<function_independent(); 28 | ios[0]->flush(); 29 | ios[1]->flush(); 30 | t2 = time_from(start); 31 | if(party == 1) cout <<"FUNC_IND:\t"<function_dependent(); 35 | ios[0]->flush(); 36 | ios[1]->flush(); 37 | t2 = time_from(start); 38 | if(party == 1) cout <<"FUNC_DEP:\t"<(ios)/1000.0/1000.0<<" MB"<online(in, out); 45 | ios[0]->flush(); 46 | ios[1]->flush(); 47 | t2 = time_from(start); 48 | // uint64_t band2 = io.count(); 49 | // if(party == 1)cout <<"bandwidth\t"<(ios)/1000.0/1000.0<<" MB"< 2 | #include "emp-agmpc/emp-agmpc.h" 3 | 4 | #include "emp-agmpc/flexible_input_output.h" 5 | 6 | using namespace std; 7 | using namespace emp; 8 | 9 | const string filename = macro_xstr(EMP_CIRCUIT_PATH) + string("bristol_format/AES-non-expanded.txt"); 10 | 11 | const static int nP = 2; 12 | int party, port; 13 | 14 | void test_non_in_out(int party, int port) { 15 | cout << "Standard in/out without using FlexIn/FlexOut" << endl; 16 | cout << "compute: K = E_{010101...}(101010...); E_{010101...}(K)" << endl; 17 | PRG prg; 18 | bool delta[128]; 19 | prg.random_bool(delta, 128); 20 | NetIOMP io(party, port); 21 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 22 | 23 | NetIOMP *ios[2] = {&io, &io2}; 24 | ThreadPool pool(2*(nP-1)+2); 25 | 26 | BristolFormat cf(filename.c_str()); 27 | 28 | CMPC* mpc = new CMPC(ios, &pool, party, &cf, delta); 29 | ios[0]->flush(); 30 | ios[1]->flush(); 31 | 32 | mpc->function_independent(); 33 | ios[0]->flush(); 34 | ios[1]->flush(); 35 | 36 | mpc->function_dependent(); 37 | ios[0]->flush(); 38 | ios[1]->flush(); 39 | 40 | bool *in = new bool[cf.n1+cf.n2]; 41 | memset(in, false, cf.n1+cf.n2); 42 | bool *out = new bool[cf.n3]; 43 | 44 | if(party == ALICE) { 45 | for (int i = 0; i < cf.n1; i++) { 46 | in[i] = i % 2 == 0; 47 | } 48 | } else if (party == BOB){ 49 | for (int i = 0; i < cf.n2; i++) { 50 | in[cf.n1 + i] = i % 2 == 1; 51 | } 52 | } 53 | 54 | mpc->online(in, out); 55 | ios[0]->flush(); 56 | ios[1]->flush(); 57 | 58 | delete mpc; 59 | 60 | CMPC* mpc2 = new CMPC(ios, &pool, party, &cf, delta); 61 | ios[0]->flush(); 62 | ios[1]->flush(); 63 | 64 | mpc2->function_independent(); 65 | ios[0]->flush(); 66 | ios[1]->flush(); 67 | 68 | mpc2->function_dependent(); 69 | ios[0]->flush(); 70 | ios[1]->flush(); 71 | 72 | bool *in2 = new bool[cf.n1+cf.n2]; 73 | memset(in2, false, cf.n1+cf.n2); 74 | bool *out2 = new bool[cf.n3]; 75 | 76 | if(party == ALICE) { 77 | for (int i = 0; i < cf.n1; i++) { 78 | in2[i] = out[i]; 79 | } 80 | } else if (party == BOB){ 81 | for (int i = 0; i < cf.n2; i++) { 82 | in2[cf.n1 + i] = i % 2 == 1; 83 | } 84 | } 85 | 86 | mpc2->online(in2, out2); 87 | ios[0]->flush(); 88 | ios[1]->flush(); 89 | 90 | if(party == ALICE) { 91 | cout << "output:" << endl; 92 | for (int i = 0; i < cf.n3; i++) { 93 | cout << out2[i] << " "; 94 | } 95 | cout << endl; 96 | } 97 | 98 | delete mpc2; 99 | } 100 | 101 | void test_in_out(int party, int port) { 102 | cout << "FlexIn/FlexOut" << endl; 103 | cout << "compute: K = E_{010101...}(101010...); E_{010101...}(K)" << endl; 104 | PRG prg; 105 | bool delta[128]; 106 | prg.random_bool(delta, 128); 107 | 108 | NetIOMP io(party, port); 109 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 110 | 111 | NetIOMP *ios[2] = {&io, &io2}; 112 | ThreadPool pool(2*(nP-1)+2); 113 | 114 | BristolFormat cf(filename.c_str()); 115 | 116 | CMPC* mpc = new CMPC(ios, &pool, party, &cf, delta); 117 | ios[0]->flush(); 118 | ios[1]->flush(); 119 | 120 | mpc->function_independent(); 121 | ios[0]->flush(); 122 | ios[1]->flush(); 123 | 124 | mpc->function_dependent(); 125 | ios[0]->flush(); 126 | ios[1]->flush(); 127 | 128 | FlexIn in(cf.n1 + cf.n2, party); 129 | for(int i = 0; i < 64; i++) { 130 | in.assign_party(i, ALICE); 131 | } 132 | for(int i = 64; i < cf.n1; i++) { 133 | in.assign_party(i, -2); 134 | } 135 | for(int i = 0; i < 64; i++) { 136 | in.assign_party(cf.n1 + i, 0); 137 | } 138 | for(int i = 64; i < cf.n2; i++) { 139 | in.assign_party(cf.n1 + i, BOB); 140 | } 141 | 142 | FlexOut out(cf.n3, party); 143 | for(int i = 0; i < cf.n3; i++) { 144 | out.assign_party(i, -1); 145 | } 146 | 147 | if(party == ALICE) { 148 | for(int i = 0; i < 64; i++){ 149 | in.assign_plaintext_bit(i, i % 2 == 0); 150 | } 151 | for(int i = 64; i < cf.n1; i++){ 152 | in.assign_plaintext_bit(i, i % 2 == 0); 153 | } 154 | for(int i = 0; i < 64; i++) { 155 | in.assign_plaintext_bit(cf.n1 + i, i % 2 == 1); 156 | } 157 | } else { 158 | for(int i = 64; i < cf.n1; i++){ 159 | in.assign_plaintext_bit(i, false); 160 | } 161 | for(int i = 0; i < 64; i++) { 162 | in.assign_plaintext_bit(cf.n1 + i, i % 2 == 1); 163 | } 164 | for(int i = 64; i < cf.n2; i++) { 165 | in.assign_plaintext_bit(cf.n1 + i, i % 2 == 1); 166 | } 167 | } 168 | 169 | mpc->online(&in, &out); 170 | ios[0]->flush(); 171 | ios[1]->flush(); 172 | 173 | CMPC* mpc2 = new CMPC(ios, &pool, party, &cf, delta); 174 | ios[0]->flush(); 175 | ios[1]->flush(); 176 | 177 | mpc2->function_independent(); 178 | ios[0]->flush(); 179 | ios[1]->flush(); 180 | 181 | mpc2->function_dependent(); 182 | ios[0]->flush(); 183 | ios[1]->flush(); 184 | 185 | FlexIn in2(cf.n1 + cf.n2, party); 186 | for(int i = 0; i < cf.n1; i++) { 187 | in2.assign_party(i, -1); 188 | } 189 | for(int i = cf.n1; i < cf.n1 + cf.n2; i++) { 190 | in2.assign_party(i, BOB); 191 | } 192 | 193 | FlexOut out2(cf.n3, party); 194 | for(int i = 0; i < 32; i++) { 195 | out2.assign_party(i, ALICE); 196 | } 197 | for(int i = 32; i < 64; i++) { 198 | out2.assign_party(i, BOB); 199 | } 200 | for(int i = 64; i < cf.n3; i++) { 201 | out2.assign_party(i, 0); 202 | } 203 | 204 | for(int i = 0; i < cf.n1; i++) { 205 | AuthBitShare mabit = out.get_authenticated_bitshare(i); 206 | in2.assign_authenticated_bitshare(i, &mabit); 207 | } 208 | 209 | if(party == BOB) { 210 | for(int i = 0; i < cf.n2; i++) { 211 | in2.assign_plaintext_bit(cf.n1 + i, i % 2 == 1); 212 | } 213 | } 214 | 215 | mpc2->online(&in2, &out2); 216 | ios[0]->flush(); 217 | ios[1]->flush(); 218 | 219 | cout << "output:" << endl; 220 | if(party == ALICE) { 221 | for (int i = 0; i < 32; i++) { 222 | cout << out2.get_plaintext_bit(i) << " "; 223 | } 224 | for (int i = 32; i < 64; i++) { 225 | cout << "x" << " "; 226 | } 227 | for (int i = 64; i < cf.n3; i++) { 228 | cout << out2.get_plaintext_bit(i) << " "; 229 | } 230 | } else { 231 | for (int i = 0; i < 32; i++) { 232 | cout << "x" << " "; 233 | } 234 | for (int i = 32; i < 64; i++) { 235 | cout << out2.get_plaintext_bit(i) << " "; 236 | } 237 | for (int i = 64; i < cf.n3; i++) { 238 | cout << out2.get_plaintext_bit(i) << " "; 239 | } 240 | } 241 | cout << endl; 242 | 243 | delete mpc; 244 | delete mpc2; 245 | } 246 | 247 | int main(int argc, char** argv) { 248 | parse_party_and_port(argv, &party, &port); 249 | if(party > nP)return 0; 250 | 251 | test_non_in_out(party, port); 252 | 253 | cout << "============================" << endl; 254 | 255 | test_in_out(party, port); 256 | 257 | return 0; 258 | } -------------------------------------------------------------------------------- /test/test_mpc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emp-agmpc/emp-agmpc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH) + string("bristol_format/"); 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 | const static int nP = 3; 14 | NetIOMP io(party, port); 15 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 16 | NetIOMP *ios[2] = {&io, &io2}; 17 | ThreadPool pool(4); 18 | string file = circuit_file_location+"/AES-non-expanded.txt"; 19 | file = circuit_file_location+"/sha-1.txt"; 20 | BristolFormat cf(file.c_str()); 21 | 22 | CMPC* mpc = new CMPC(ios, &pool, party, &cf); 23 | cout <<"Setup:\t"<function_independent(); 26 | cout <<"FUNC_IND:\t"<function_dependent(); 29 | cout <<"FUNC_DEP:\t"<online(in, out); 34 | uint64_t band2 = io.count(); 35 | cout <<"bandwidth\t"< 2 | #include "emp-agmpc/emp-agmpc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | const string circuit_file_location = macro_xstr(EMP_CIRCUIT_PATH) + string("bristol_format/"); 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 | const static int nP = 3; 14 | int start[] = {0, 0, 32, 64}; 15 | int end[] = {0, 32, 64, 512}; 16 | int start2[] = {0, 0, 64, 64}; 17 | int end2[] = {0, 64, 65, 512}; 18 | 19 | NetIOMP io(party, port); 20 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 21 | NetIOMP *ios[2] = {&io, &io2}; 22 | ThreadPool pool(4); 23 | string file = circuit_file_location+"/AES-non-expanded.txt"; 24 | file = circuit_file_location+"/sha-1.txt"; 25 | BristolFormat cf(file.c_str()); 26 | 27 | CMPC* mpc = new CMPC(ios, &pool, party, &cf); 28 | cout <<"Setup:\t"<function_independent(); 31 | cout <<"FUNC_IND:\t"<function_dependent(); 34 | cout <<"FUNC_DEP:\t"<online(in, out, start, end); 43 | // else 44 | // mpc->online(in, out, start2, end2); 45 | uint64_t band2 = io.count(); 46 | cout <<"bandwidth\t"< 2 | #include "emp-agmpc/emp-agmpc.h" 3 | using namespace std; 4 | using namespace emp; 5 | 6 | const static int nP = 3; 7 | int party, port; 8 | int main(int argc, char** argv) { 9 | parse_party_and_port(argv, &party, &port); 10 | if(party > nP)return 0; 11 | NetIOMP io(party, port); 12 | #ifdef LOCALHOST 13 | NetIOMP io2(party, port+2*(nP+1)*(nP+1)+1); 14 | #else 15 | NetIOMP io2(party, port+2*(nP+1)); 16 | #endif 17 | NetIOMP *ios[2] = {&io, &io2}; 18 | 19 | ThreadPool pool(2*(nP-1)+2); 20 | FpreMP mp(ios, &pool, party); 21 | 22 | int num_ands = 1<<15; 23 | block * mac[nP+1]; 24 | block * key[nP+1]; 25 | bool * value; 26 | 27 | for(int i = 1; i <= nP; ++i) { 28 | key[i] = new block[num_ands*3]; 29 | mac[i] = new block[num_ands*3]; 30 | } 31 | value = new bool[num_ands*3]; 32 | auto t1 = clock_start(); 33 | mp.compute(mac, key, value, num_ands); 34 | cout <<"Gates: "<