online.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632
  1. #include <bsd/stdlib.h> // arc4random_buf
  2. #include "online.hpp"
  3. #include "mpcops.hpp"
  4. #include "rdpf.hpp"
  5. #include "duoram.hpp"
  6. #include "cdpf.hpp"
  7. #include "cell.hpp"
  8. #include "shapes.hpp"
  9. #include "bst.hpp"
  10. #include "avl.hpp"
  11. static void online_test(MPCIO &mpcio,
  12. const PRACOptions &opts, char **args)
  13. {
  14. nbits_t nbits = VALUE_BITS;
  15. if (*args) {
  16. nbits = atoi(*args);
  17. }
  18. size_t as_memsize = 9;
  19. size_t xs_memsize = 3;
  20. MPCTIO tio(mpcio, 0);
  21. bool is_server = (mpcio.player == 2);
  22. RegAS *A = new RegAS[as_memsize];
  23. RegXS *AX = new RegXS[xs_memsize];
  24. value_t V;
  25. RegBS F0, F1, F2;
  26. RegBS FA, FO, FS;
  27. RegXS X;
  28. if (!is_server) {
  29. A[0].randomize();
  30. A[1].randomize();
  31. F0.randomize();
  32. A[4].randomize();
  33. F1.randomize();
  34. F2.randomize();
  35. A[6].randomize();
  36. A[7].randomize();
  37. X.randomize();
  38. AX[0].randomize();
  39. AX[1].randomize();
  40. arc4random_buf(&V, sizeof(V));
  41. printf("A:\n"); for (size_t i=0; i<as_memsize; ++i) printf("%3lu: %016lX\n", i, A[i].ashare);
  42. printf("AX:\n"); for (size_t i=0; i<xs_memsize; ++i) printf("%3lu: %016lX\n", i, AX[i].xshare);
  43. printf("V : %016lX\n", V);
  44. printf("F0 : %01X\n", F0.bshare);
  45. printf("F1 : %01X\n", F1.bshare);
  46. printf("F2 : %01X\n", F2.bshare);
  47. printf("X : %016lX\n", X.xshare);
  48. }
  49. std::vector<coro_t> coroutines;
  50. coroutines.emplace_back(
  51. [&tio, &A, nbits](yield_t &yield) {
  52. mpc_mul(tio, yield, A[2], A[0], A[1], nbits);
  53. });
  54. coroutines.emplace_back(
  55. [&tio, &A, V, nbits](yield_t &yield) {
  56. mpc_valuemul(tio, yield, A[3], V, nbits);
  57. });
  58. coroutines.emplace_back(
  59. [&tio, &A, &F0, nbits](yield_t &yield) {
  60. mpc_flagmult(tio, yield, A[5], F0, A[4], nbits);
  61. });
  62. coroutines.emplace_back(
  63. [&tio, &A, &F1, nbits](yield_t &yield) {
  64. mpc_oswap(tio, yield, A[6], A[7], F1, nbits);
  65. });
  66. coroutines.emplace_back(
  67. [&tio, &A, &X, nbits](yield_t &yield) {
  68. mpc_xs_to_as(tio, yield, A[8], X, nbits);
  69. });
  70. coroutines.emplace_back(
  71. [&tio, &AX, &F0, nbits](yield_t &yield) {
  72. mpc_select(tio, yield, AX[2], F0, AX[0], AX[1], nbits);
  73. });
  74. coroutines.emplace_back(
  75. [&tio, &FA, &F0, &F1](yield_t &yield) {
  76. mpc_and(tio, yield, FA, F0, F1);
  77. });
  78. coroutines.emplace_back(
  79. [&tio, &FO, &F0, &F1](yield_t &yield) {
  80. mpc_or(tio, yield, FO, F0, F1);
  81. });
  82. coroutines.emplace_back(
  83. [&tio, &FS, &F0, &F1, &F2](yield_t &yield) {
  84. mpc_select(tio, yield, FS, F2, F0, F1);
  85. });
  86. run_coroutines(tio, coroutines);
  87. if (!is_server) {
  88. printf("\n");
  89. printf("A:\n"); for (size_t i=0; i<as_memsize; ++i) printf("%3lu: %016lX\n", i, A[i].ashare);
  90. printf("AX:\n"); for (size_t i=0; i<xs_memsize; ++i) printf("%3lu: %016lX\n", i, AX[i].xshare);
  91. }
  92. // Check the answers
  93. if (mpcio.player == 1) {
  94. tio.queue_peer(A, as_memsize*sizeof(RegAS));
  95. tio.queue_peer(AX, xs_memsize*sizeof(RegXS));
  96. tio.queue_peer(&V, sizeof(V));
  97. tio.queue_peer(&F0, sizeof(RegBS));
  98. tio.queue_peer(&F1, sizeof(RegBS));
  99. tio.queue_peer(&F2, sizeof(RegBS));
  100. tio.queue_peer(&FA, sizeof(RegBS));
  101. tio.queue_peer(&FO, sizeof(RegBS));
  102. tio.queue_peer(&FS, sizeof(RegBS));
  103. tio.queue_peer(&X, sizeof(RegXS));
  104. tio.send();
  105. } else if (mpcio.player == 0) {
  106. RegAS *B = new RegAS[as_memsize];
  107. RegXS *BAX = new RegXS[xs_memsize];
  108. RegBS BF0, BF1, BF2;
  109. RegBS BFA, BFO, BFS;
  110. RegXS BX;
  111. value_t BV;
  112. value_t *S = new value_t[as_memsize];
  113. value_t *Y = new value_t[xs_memsize];
  114. bit_t SF0, SF1, SF2;
  115. bit_t SFA, SFO, SFS;
  116. value_t SX;
  117. tio.recv_peer(B, as_memsize*sizeof(RegAS));
  118. tio.recv_peer(BAX, xs_memsize*sizeof(RegXS));
  119. tio.recv_peer(&BV, sizeof(BV));
  120. tio.recv_peer(&BF0, sizeof(RegBS));
  121. tio.recv_peer(&BF1, sizeof(RegBS));
  122. tio.recv_peer(&BF2, sizeof(RegBS));
  123. tio.recv_peer(&BFA, sizeof(RegBS));
  124. tio.recv_peer(&BFO, sizeof(RegBS));
  125. tio.recv_peer(&BFS, sizeof(RegBS));
  126. tio.recv_peer(&BX, sizeof(RegXS));
  127. for(size_t i=0; i<as_memsize; ++i) S[i] = A[i].ashare+B[i].ashare;
  128. for(size_t i=0; i<xs_memsize; ++i) Y[i] = AX[i].xshare^BAX[i].xshare;
  129. SF0 = F0.bshare ^ BF0.bshare;
  130. SF1 = F1.bshare ^ BF1.bshare;
  131. SF2 = F2.bshare ^ BF2.bshare;
  132. SFA = FA.bshare ^ BFA.bshare;
  133. SFO = FO.bshare ^ BFO.bshare;
  134. SFS = FS.bshare ^ BFS.bshare;
  135. SX = X.xshare ^ BX.xshare;
  136. printf("S:\n"); for (size_t i=0; i<as_memsize; ++i) printf("%3lu: %016lX\n", i, S[i]);
  137. printf("Y:\n"); for (size_t i=0; i<xs_memsize; ++i) printf("%3lu: %016lX\n", i, Y[i]);
  138. printf("SF0: %01X\n", SF0);
  139. printf("SF1: %01X\n", SF1);
  140. printf("SF2: %01X\n", SF2);
  141. printf("SFA: %01X\n", SFA);
  142. printf("SFO: %01X\n", SFO);
  143. printf("SFS: %01X\n", SFS);
  144. printf("SX : %016lX\n", SX);
  145. printf("\n%016lx\n", S[0]*S[1]-S[2]);
  146. printf("%016lx\n", (V*BV)-S[3]);
  147. printf("%016lx\n", (SF0*S[4])-S[5]);
  148. printf("%016lx\n", S[8]-SX);
  149. delete[] B;
  150. delete[] S;
  151. }
  152. delete[] A;
  153. delete[] AX;
  154. }
  155. static void lamport_test(MPCIO &mpcio,
  156. const PRACOptions &opts, char **args)
  157. {
  158. // Create a bunch of threads and send a bunch of data to the other
  159. // peer, and receive their data. If an arg is specified, repeat
  160. // that many times. The Lamport clock at the end should be just the
  161. // number of repetitions. Subsequent args are the chunk size and
  162. // the number of chunks per message
  163. size_t niters = 1;
  164. size_t chunksize = 1<<20;
  165. size_t numchunks = 1;
  166. if (*args) {
  167. niters = atoi(*args);
  168. ++args;
  169. }
  170. if (*args) {
  171. chunksize = atoi(*args);
  172. ++args;
  173. }
  174. if (*args) {
  175. numchunks = atoi(*args);
  176. ++args;
  177. }
  178. int num_threads = opts.num_threads;
  179. boost::asio::thread_pool pool(num_threads);
  180. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  181. boost::asio::post(pool, [&mpcio, thread_num, niters, chunksize, numchunks] {
  182. MPCTIO tio(mpcio, thread_num);
  183. char *sendbuf = new char[chunksize];
  184. char *recvbuf = new char[chunksize*numchunks];
  185. for (size_t i=0; i<niters; ++i) {
  186. for (size_t chunk=0; chunk<numchunks; ++chunk) {
  187. arc4random_buf(sendbuf, chunksize);
  188. tio.queue_peer(sendbuf, chunksize);
  189. }
  190. tio.send();
  191. tio.recv_peer(recvbuf, chunksize*numchunks);
  192. }
  193. delete[] recvbuf;
  194. delete[] sendbuf;
  195. });
  196. }
  197. pool.join();
  198. }
  199. template <nbits_t WIDTH>
  200. static void rdpf_test(MPCIO &mpcio,
  201. const PRACOptions &opts, char **args, bool incremental)
  202. {
  203. nbits_t depth=6;
  204. size_t num_iters = 1;
  205. if (*args) {
  206. depth = atoi(*args);
  207. ++args;
  208. }
  209. if (*args) {
  210. num_iters = atoi(*args);
  211. ++args;
  212. }
  213. MPCTIO tio(mpcio, 0, opts.num_threads);
  214. run_coroutines(tio, [&tio, depth, num_iters, incremental] (yield_t &yield) {
  215. size_t &aes_ops = tio.aes_ops();
  216. nbits_t min_level = incremental ? 1 : depth;
  217. for (size_t iter=0; iter < num_iters; ++iter) {
  218. if (tio.player() == 2) {
  219. RDPFPair<WIDTH> dp = tio.rdpfpair<WIDTH>(yield, depth,
  220. incremental);
  221. for (int i=0;i<2;++i) {
  222. RDPF<WIDTH> &dpf = dp.dpf[i];
  223. for (nbits_t level=min_level; level<=depth; ++level) {
  224. if (incremental) {
  225. printf("Level = %u\n\n", level);
  226. dpf.depth(level);
  227. }
  228. for (address_t x=0;x<(address_t(1)<<level);++x) {
  229. typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
  230. RegBS ub = dpf.unit_bs(leaf);
  231. RegAS ua = dpf.unit_as(leaf);
  232. typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
  233. typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
  234. printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
  235. for (nbits_t j=0;j<WIDTH;++j) {
  236. printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
  237. }
  238. printf("\n");
  239. }
  240. printf("\n");
  241. }
  242. }
  243. } else {
  244. RDPFTriple<WIDTH> dt = tio.rdpftriple<WIDTH>(yield,
  245. depth, incremental);
  246. for (int i=0;i<3;++i) {
  247. RDPF<WIDTH> &dpf = dt.dpf[i];
  248. for (nbits_t level=min_level; level<=depth; ++level) {
  249. if (incremental) {
  250. printf("Level = %u\n", level);
  251. dt.depth(level);
  252. RegXS tshare;
  253. dt.get_target(tshare);
  254. printf("Target share = %lx\n\n", tshare.share());
  255. }
  256. typename RDPF<WIDTH>::RegXSW peer_scaled_xor;
  257. typename RDPF<WIDTH>::RegASW peer_scaled_sum;
  258. if (tio.player() == 1) {
  259. tio.iostream_peer() <<
  260. dpf.li[depth-level].scaled_xor <<
  261. dpf.li[depth-level].scaled_sum;
  262. } else {
  263. tio.iostream_peer() >> peer_scaled_xor >> peer_scaled_sum;
  264. peer_scaled_sum += dpf.li[depth-level].scaled_sum;
  265. peer_scaled_xor ^= dpf.li[depth-level].scaled_xor;
  266. }
  267. for (address_t x=0;x<(address_t(1)<<level);++x) {
  268. typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
  269. RegBS ub = dpf.unit_bs(leaf);
  270. RegAS ua = dpf.unit_as(leaf);
  271. typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
  272. typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
  273. printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
  274. for (nbits_t j=0;j<WIDTH;++j) {
  275. printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
  276. }
  277. printf("\n");
  278. if (tio.player() == 1) {
  279. tio.iostream_peer() << ub << ua << sx << sa;
  280. } else {
  281. RegBS peer_ub;
  282. RegAS peer_ua;
  283. typename RDPF<WIDTH>::RegXSW peer_sx;
  284. typename RDPF<WIDTH>::RegASW peer_sa;
  285. tio.iostream_peer() >> peer_ub >> peer_ua >>
  286. peer_sx >> peer_sa;
  287. ub ^= peer_ub;
  288. ua += peer_ua;
  289. sx ^= peer_sx;
  290. sa += peer_sa;
  291. bool is_nonzero = ub.bshare || ua.ashare;
  292. for (nbits_t j=0;j<WIDTH;++j) {
  293. is_nonzero |= (sx[j].xshare || sa[j].ashare);
  294. }
  295. if (is_nonzero) {
  296. printf("**** %x %016lx", ub.bshare, ua.ashare);
  297. for (nbits_t j=0;j<WIDTH;++j) {
  298. printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
  299. }
  300. printf("\nSCALE ");
  301. for (nbits_t j=0;j<WIDTH;++j) {
  302. printf(" %016lx %016lx",
  303. peer_scaled_xor[j].xshare,
  304. peer_scaled_sum[j].ashare);
  305. }
  306. printf("\n");
  307. }
  308. }
  309. }
  310. printf("\n");
  311. }
  312. }
  313. }
  314. }
  315. });
  316. }
  317. static void rdpf_timing(MPCIO &mpcio,
  318. const PRACOptions &opts, char **args)
  319. {
  320. nbits_t depth=6;
  321. if (*args) {
  322. depth = atoi(*args);
  323. ++args;
  324. }
  325. int num_threads = opts.num_threads;
  326. boost::asio::thread_pool pool(num_threads);
  327. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  328. boost::asio::post(pool, [&mpcio, thread_num, depth] {
  329. MPCTIO tio(mpcio, thread_num);
  330. run_coroutines(tio, [&tio, depth] (yield_t &yield) {
  331. size_t &aes_ops = tio.aes_ops();
  332. if (tio.player() == 2) {
  333. RDPFPair<1> dp = tio.rdpfpair(yield, depth);
  334. for (int i=0;i<2;++i) {
  335. RDPF<1> &dpf = dp.dpf[i];
  336. dpf.expand(aes_ops);
  337. RDPF<1>::RegXSW scaled_xor;
  338. for (address_t x=0;x<(address_t(1)<<depth);++x) {
  339. RDPF<1>::LeafNode leaf = dpf.leaf(x, aes_ops);
  340. RDPF<1>::RegXSW sx = dpf.scaled_xs(leaf);
  341. scaled_xor ^= sx;
  342. }
  343. printf("%016lx\n%016lx\n", scaled_xor[0].xshare,
  344. dpf.li[0].scaled_xor[0].xshare);
  345. printf("\n");
  346. }
  347. } else {
  348. RDPFTriple<1> dt = tio.rdpftriple(yield, depth);
  349. for (int i=0;i<3;++i) {
  350. RDPF<1> &dpf = dt.dpf[i];
  351. dpf.expand(aes_ops);
  352. RDPF<1>::RegXSW scaled_xor;
  353. for (address_t x=0;x<(address_t(1)<<depth);++x) {
  354. RDPF<1>::LeafNode leaf = dpf.leaf(x, aes_ops);
  355. RDPF<1>::RegXSW sx = dpf.scaled_xs(leaf);
  356. scaled_xor ^= sx;
  357. }
  358. printf("%016lx\n%016lx\n", scaled_xor[0].xshare,
  359. dpf.li[0].scaled_xor[0].xshare);
  360. printf("\n");
  361. }
  362. }
  363. });
  364. });
  365. }
  366. pool.join();
  367. }
  368. static value_t parallel_streameval_rdpf(MPCIO &mpcio, const RDPF<1> &dpf,
  369. address_t start, int num_threads)
  370. {
  371. RDPF<1>::RegXSW scaled_xor[num_threads];
  372. boost::asio::thread_pool pool(num_threads);
  373. address_t totsize = (address_t(1)<<dpf.depth());
  374. address_t threadstart = start;
  375. address_t threadchunk = totsize / num_threads;
  376. address_t threadextra = totsize % num_threads;
  377. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  378. address_t threadsize = threadchunk + (address_t(thread_num) < threadextra);
  379. boost::asio::post(pool,
  380. [&mpcio, &dpf, &scaled_xor, thread_num, threadstart, threadsize] {
  381. MPCTIO tio(mpcio, thread_num);
  382. //printf("Thread %d from %X for %X\n", thread_num, threadstart, threadsize);
  383. RDPF<1>::RegXSW local_xor;
  384. size_t local_aes_ops = 0;
  385. auto ev = StreamEval(dpf, threadstart, 0, local_aes_ops);
  386. for (address_t x=0;x<threadsize;++x) {
  387. //if (x%0x10000 == 0) printf("%d", thread_num);
  388. RDPF<1>::LeafNode leaf = ev.next();
  389. local_xor ^= dpf.scaled_xs(leaf);
  390. }
  391. scaled_xor[thread_num] = local_xor;
  392. tio.aes_ops() += local_aes_ops;
  393. //printf("Thread %d complete\n", thread_num);
  394. });
  395. threadstart = (threadstart + threadsize) % totsize;
  396. }
  397. pool.join();
  398. RDPF<1>::RegXSW res;
  399. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  400. res ^= scaled_xor[thread_num];
  401. }
  402. return res[0].xshare;
  403. }
  404. static void rdpfeval_timing(MPCIO &mpcio,
  405. const PRACOptions &opts, char **args)
  406. {
  407. nbits_t depth=6;
  408. address_t start=0;
  409. if (*args) {
  410. depth = atoi(*args);
  411. ++args;
  412. }
  413. if (*args) {
  414. start = strtoull(*args, NULL, 16);
  415. ++args;
  416. }
  417. int num_threads = opts.num_threads;
  418. MPCTIO tio(mpcio, 0, num_threads);
  419. run_coroutines(tio, [&mpcio, &tio, depth, start, num_threads] (yield_t &yield) {
  420. if (tio.player() == 2) {
  421. RDPFPair<1> dp = tio.rdpfpair(yield, depth);
  422. for (int i=0;i<2;++i) {
  423. RDPF<1> &dpf = dp.dpf[i];
  424. value_t scaled_xor =
  425. parallel_streameval_rdpf(mpcio, dpf, start, num_threads);
  426. printf("%016lx\n%016lx\n", scaled_xor,
  427. dpf.li[0].scaled_xor[0].xshare);
  428. printf("\n");
  429. }
  430. } else {
  431. RDPFTriple<1> dt = tio.rdpftriple(yield, depth);
  432. for (int i=0;i<3;++i) {
  433. RDPF<1> &dpf = dt.dpf[i];
  434. value_t scaled_xor =
  435. parallel_streameval_rdpf(mpcio, dpf, start, num_threads);
  436. printf("%016lx\n%016lx\n", scaled_xor,
  437. dpf.li[0].scaled_xor[0].xshare);
  438. printf("\n");
  439. }
  440. }
  441. });
  442. }
  443. static void par_rdpfeval_timing(MPCIO &mpcio,
  444. const PRACOptions &opts, char **args)
  445. {
  446. nbits_t depth=6;
  447. address_t start=0;
  448. if (*args) {
  449. depth = atoi(*args);
  450. ++args;
  451. }
  452. if (*args) {
  453. start = strtoull(*args, NULL, 16);
  454. ++args;
  455. }
  456. int num_threads = opts.num_threads;
  457. MPCTIO tio(mpcio, 0, num_threads);
  458. run_coroutines(tio, [&tio, depth, start, num_threads] (yield_t &yield) {
  459. if (tio.player() == 2) {
  460. RDPFPair<1> dp = tio.rdpfpair(yield, depth);
  461. for (int i=0;i<2;++i) {
  462. RDPF<1> &dpf = dp.dpf[i];
  463. nbits_t depth = dpf.depth();
  464. auto pe = ParallelEval(dpf, start, 0,
  465. address_t(1)<<depth, num_threads, tio.aes_ops());
  466. RDPF<1>::RegXSW result, init;
  467. result = pe.reduce(init, [&dpf] (int thread_num,
  468. address_t i, const RDPF<1>::LeafNode &leaf) {
  469. return dpf.scaled_xs(leaf);
  470. });
  471. printf("%016lx\n%016lx\n", result[0].xshare,
  472. dpf.li[0].scaled_xor[0].xshare);
  473. printf("\n");
  474. }
  475. } else {
  476. RDPFTriple<1> dt = tio.rdpftriple(yield, depth);
  477. for (int i=0;i<3;++i) {
  478. RDPF<1> &dpf = dt.dpf[i];
  479. nbits_t depth = dpf.depth();
  480. auto pe = ParallelEval(dpf, start, 0,
  481. address_t(1)<<depth, num_threads, tio.aes_ops());
  482. RDPF<1>::RegXSW result, init;
  483. result = pe.reduce(init, [&dpf] (int thread_num,
  484. address_t i, const RDPF<1>::LeafNode &leaf) {
  485. return dpf.scaled_xs(leaf);
  486. });
  487. printf("%016lx\n%016lx\n", result[0].xshare,
  488. dpf.li[0].scaled_xor[0].xshare);
  489. printf("\n");
  490. }
  491. }
  492. });
  493. }
  494. static void tupleeval_timing(MPCIO &mpcio,
  495. const PRACOptions &opts, char **args)
  496. {
  497. nbits_t depth=6;
  498. address_t start=0;
  499. if (*args) {
  500. depth = atoi(*args);
  501. ++args;
  502. }
  503. if (*args) {
  504. start = atoi(*args);
  505. ++args;
  506. }
  507. int num_threads = opts.num_threads;
  508. MPCTIO tio(mpcio, 0, num_threads);
  509. run_coroutines(tio, [&tio, depth, start] (yield_t &yield) {
  510. size_t &aes_ops = tio.aes_ops();
  511. if (tio.player() == 2) {
  512. RDPFPair<1> dp = tio.rdpfpair(yield, depth);
  513. RDPF<1>::RegXSW scaled_xor0, scaled_xor1;
  514. auto ev = StreamEval(dp, start, 0, aes_ops, false);
  515. for (address_t x=0;x<(address_t(1)<<depth);++x) {
  516. auto [L0, L1] = ev.next();
  517. RDPF<1>::RegXSW sx0 = dp.dpf[0].scaled_xs(L0);
  518. RDPF<1>::RegXSW sx1 = dp.dpf[1].scaled_xs(L1);
  519. scaled_xor0 ^= sx0;
  520. scaled_xor1 ^= sx1;
  521. }
  522. printf("%016lx\n%016lx\n", scaled_xor0[0].xshare,
  523. dp.dpf[0].li[0].scaled_xor[0].xshare);
  524. printf("\n");
  525. printf("%016lx\n%016lx\n", scaled_xor1[0].xshare,
  526. dp.dpf[1].li[0].scaled_xor[0].xshare);
  527. printf("\n");
  528. } else {
  529. RDPFTriple<1> dt = tio.rdpftriple(yield, depth);
  530. RDPF<1>::RegXSW scaled_xor0, scaled_xor1, scaled_xor2;
  531. auto ev = StreamEval(dt, start, 0, aes_ops, false);
  532. for (address_t x=0;x<(address_t(1)<<depth);++x) {
  533. auto [L0, L1, L2] = ev.next();
  534. RDPF<1>::RegXSW sx0 = dt.dpf[0].scaled_xs(L0);
  535. RDPF<1>::RegXSW sx1 = dt.dpf[1].scaled_xs(L1);
  536. RDPF<1>::RegXSW sx2 = dt.dpf[2].scaled_xs(L2);
  537. scaled_xor0 ^= sx0;
  538. scaled_xor1 ^= sx1;
  539. scaled_xor2 ^= sx2;
  540. }
  541. printf("%016lx\n%016lx\n", scaled_xor0[0].xshare,
  542. dt.dpf[0].li[0].scaled_xor[0].xshare);
  543. printf("\n");
  544. printf("%016lx\n%016lx\n", scaled_xor1[0].xshare,
  545. dt.dpf[1].li[0].scaled_xor[0].xshare);
  546. printf("\n");
  547. printf("%016lx\n%016lx\n", scaled_xor2[0].xshare,
  548. dt.dpf[2].li[0].scaled_xor[0].xshare);
  549. printf("\n");
  550. }
  551. });
  552. }
  553. static void par_tupleeval_timing(MPCIO &mpcio,
  554. const PRACOptions &opts, char **args)
  555. {
  556. nbits_t depth=6;
  557. address_t start=0;
  558. if (*args) {
  559. depth = atoi(*args);
  560. ++args;
  561. }
  562. if (*args) {
  563. start = atoi(*args);
  564. ++args;
  565. }
  566. int num_threads = opts.num_threads;
  567. MPCTIO tio(mpcio, 0, num_threads);
  568. run_coroutines(tio, [&tio, depth, start, num_threads] (yield_t &yield) {
  569. size_t &aes_ops = tio.aes_ops();
  570. if (tio.player() == 2) {
  571. RDPFPair<1> dp = tio.rdpfpair(yield, depth);
  572. auto pe = ParallelEval(dp, start, 0, address_t(1)<<depth,
  573. num_threads, aes_ops);
  574. RDPFPair<1>::RegXSWP result, init;
  575. result = pe.reduce(init, [&dp] (int thread_num, address_t i,
  576. const RDPFPair<1>::LeafNode &leaf) {
  577. RDPFPair<1>::RegXSWP scaled;
  578. dp.scaled(scaled, leaf);
  579. return scaled;
  580. });
  581. printf("%016lx\n%016lx\n", std::get<0>(result)[0].xshare,
  582. dp.dpf[0].li[0].scaled_xor[0].xshare);
  583. printf("\n");
  584. printf("%016lx\n%016lx\n", std::get<1>(result)[0].xshare,
  585. dp.dpf[1].li[0].scaled_xor[0].xshare);
  586. printf("\n");
  587. } else {
  588. RDPFTriple<1> dt = tio.rdpftriple(yield, depth);
  589. auto pe = ParallelEval(dt, start, 0, address_t(1)<<depth,
  590. num_threads, aes_ops);
  591. RDPFTriple<1>::RegXSWT result, init;
  592. result = pe.reduce(init, [&dt] (int thread_num, address_t i,
  593. const RDPFTriple<1>::LeafNode &leaf) {
  594. RDPFTriple<1>::RegXSWT scaled;
  595. dt.scaled(scaled, leaf);
  596. return scaled;
  597. });
  598. printf("%016lx\n%016lx\n", std::get<0>(result)[0].xshare,
  599. dt.dpf[0].li[0].scaled_xor[0].xshare);
  600. printf("\n");
  601. printf("%016lx\n%016lx\n", std::get<1>(result)[0].xshare,
  602. dt.dpf[1].li[0].scaled_xor[0].xshare);
  603. printf("\n");
  604. printf("%016lx\n%016lx\n", std::get<2>(result)[0].xshare,
  605. dt.dpf[2].li[0].scaled_xor[0].xshare);
  606. printf("\n");
  607. }
  608. });
  609. }
  610. // T is RegAS or RegXS for additive or XOR shared database respectively
  611. template <typename T>
  612. static void duoram_test(MPCIO &mpcio,
  613. const PRACOptions &opts, char **args)
  614. {
  615. nbits_t depth=6;
  616. address_t share=arc4random();
  617. if (*args) {
  618. depth = atoi(*args);
  619. ++args;
  620. }
  621. if (*args) {
  622. share = atoi(*args);
  623. ++args;
  624. }
  625. share &= ((address_t(1)<<depth)-1);
  626. address_t len = (1<<depth);
  627. if (*args) {
  628. len = atoi(*args);
  629. ++args;
  630. }
  631. MPCTIO tio(mpcio, 0, opts.num_threads);
  632. run_coroutines(tio, [&tio, depth, share, len] (yield_t &yield) {
  633. // size_t &aes_ops = tio.aes_ops();
  634. Duoram<T> oram(tio.player(), len);
  635. auto A = oram.flat(tio, yield);
  636. RegAS aidx, aidx2, aidx3;
  637. aidx.ashare = share;
  638. aidx2.ashare = share + tio.player();
  639. aidx3.ashare = share + 1;
  640. T M;
  641. if (tio.player() == 0) {
  642. M.set(0xbabb0000);
  643. } else {
  644. M.set(0x0000a66e);
  645. }
  646. RegXS xidx;
  647. xidx.xshare = share;
  648. T N;
  649. if (tio.player() == 0) {
  650. N.set(0xdead0000);
  651. } else {
  652. N.set(0x0000beef);
  653. }
  654. RegXS oxidx;
  655. oxidx.xshare = share+3*tio.player();
  656. T O;
  657. if (tio.player() == 0) {
  658. O.set(0x31410000);
  659. } else {
  660. O.set(0x00005926);
  661. }
  662. // Writing and reading with additively shared indices
  663. printf("Additive Updating\n");
  664. A[aidx] += M;
  665. printf("Additive Reading\n");
  666. T Aa = A[aidx];
  667. // Writing and reading with XOR shared indices
  668. printf("XOR Updating\n");
  669. A[xidx] += N;
  670. printf("XOR Reading\n");
  671. T Ax = A[xidx];
  672. // Writing and reading with OblivIndex indices
  673. auto oidx = A.oblivindex(oxidx);
  674. printf("OblivIndex Updating\n");
  675. A[oidx] += O;
  676. printf("OblivIndex Reading\n");
  677. T Ox = A[oidx];
  678. // Writing and reading with explicit indices
  679. T Ae;
  680. if (depth > 2) {
  681. printf("Explicit Updating\n");
  682. A[5] += Aa;
  683. printf("Explicit Reading\n");
  684. Ae = A[6];
  685. }
  686. // Simultaneous independent reads
  687. printf("3 independent reading\n");
  688. std::vector<T> Av = A[std::array {
  689. aidx, aidx2, aidx3
  690. }];
  691. // Simultaneous independent updates
  692. T Aw1, Aw2, Aw3;
  693. Aw1.set(0x101010101010101 * tio.player());
  694. Aw2.set(0x202020202020202 * tio.player());
  695. Aw3.set(0x303030303030303 * tio.player());
  696. printf("3 independent updating\n");
  697. A[std::array { aidx, aidx2, aidx3 }] -=
  698. std::array { Aw1, Aw2, Aw3 };
  699. if (depth <= 10) {
  700. oram.dump();
  701. auto check = A.reconstruct();
  702. if (tio.player() == 0) {
  703. for (address_t i=0;i<len;++i) {
  704. printf("%04x %016lx\n", i, check[i].share());
  705. }
  706. }
  707. }
  708. auto checkread = A.reconstruct(Aa);
  709. auto checkreade = A.reconstruct(Ae);
  710. auto checkreadx = A.reconstruct(Ax);
  711. auto checkreado = A.reconstruct(Ox);
  712. if (tio.player() == 0) {
  713. printf("Read AS value = %016lx\n", checkread.share());
  714. printf("Read AX value = %016lx\n", checkreadx.share());
  715. printf("Read Ex value = %016lx\n", checkreade.share());
  716. printf("Read OI value = %016lx\n", checkreado.share());
  717. }
  718. for (auto &v : Av) {
  719. auto checkv = A.reconstruct(v);
  720. if (tio.player() == 0) {
  721. printf("Read Av value = %016lx\n", checkv.share());
  722. }
  723. }
  724. });
  725. }
  726. // This measures the same things as the Duoram paper: dependent and
  727. // independent reads, updates, writes, and interleaves
  728. // T is RegAS or RegXS for additive or XOR shared database respectively
  729. template <typename T>
  730. static void duoram(MPCIO &mpcio,
  731. const PRACOptions &opts, char **args)
  732. {
  733. nbits_t depth = 6;
  734. int items = 4;
  735. if (*args) {
  736. depth = atoi(*args);
  737. ++args;
  738. }
  739. if (*args) {
  740. items = atoi(*args);
  741. ++args;
  742. }
  743. MPCTIO tio(mpcio, 0, opts.num_threads);
  744. run_coroutines(tio, [&mpcio, &tio, depth, items] (yield_t &yield) {
  745. size_t size = size_t(1)<<depth;
  746. address_t mask = (depth < ADDRESS_MAX_BITS ?
  747. ((address_t(1)<<depth) - 1) : ~0);
  748. Duoram<T> oram(tio.player(), size);
  749. auto A = oram.flat(tio, yield);
  750. std::cout << "===== DEPENDENT UPDATES =====\n";
  751. mpcio.reset_stats();
  752. tio.reset_lamport();
  753. // Make a linked list of length items
  754. std::vector<T> list_indices;
  755. T prev_index, next_index;
  756. prev_index.randomize(depth);
  757. for (int i=0;i<items;++i) {
  758. next_index.randomize(depth);
  759. A[next_index] += prev_index;
  760. list_indices.push_back(next_index);
  761. prev_index = next_index;
  762. }
  763. tio.sync_lamport();
  764. mpcio.dump_stats(std::cout);
  765. std::cout << "\n===== DEPENDENT READS =====\n";
  766. mpcio.reset_stats();
  767. tio.reset_lamport();
  768. // Read the linked list starting with prev_index
  769. T cur_index = prev_index;
  770. for (int i=0;i<items;++i) {
  771. cur_index = A[cur_index];
  772. }
  773. tio.sync_lamport();
  774. mpcio.dump_stats(std::cout);
  775. std::cout << "\n===== INDEPENDENT READS =====\n";
  776. mpcio.reset_stats();
  777. tio.reset_lamport();
  778. // Read all the entries in the list at once
  779. std::vector<T> read_outputs = A[list_indices];
  780. tio.sync_lamport();
  781. mpcio.dump_stats(std::cout);
  782. std::cout << "\n===== INDEPENDENT UPDATES =====\n";
  783. mpcio.reset_stats();
  784. tio.reset_lamport();
  785. // Make a vector of indices 1 larger than those in list_indices,
  786. // and a vector of values 1 larger than those in outputs
  787. std::vector<T> indep_indices, indep_values;
  788. T one;
  789. one.set(tio.player()); // Sets the shared value to 1
  790. for (int i=0;i<items;++i) {
  791. indep_indices.push_back(list_indices[i]+one);
  792. indep_values.push_back(read_outputs[i]+one);
  793. }
  794. // Update all the indices at once
  795. A[indep_indices] += indep_values;
  796. tio.sync_lamport();
  797. mpcio.dump_stats(std::cout);
  798. std::cout << "\n===== DEPENDENT WRITES =====\n";
  799. mpcio.reset_stats();
  800. tio.reset_lamport();
  801. T two;
  802. two.set(2*tio.player()); // Sets the shared value to 2
  803. // For each address addr that's number i from the end of the
  804. // linked list, write i+1 into location addr+2
  805. for (int i=0;i<items;++i) {
  806. T val;
  807. val.set((i+1)*tio.player());
  808. A[list_indices[i]+two] = val;
  809. }
  810. tio.sync_lamport();
  811. mpcio.dump_stats(std::cout);
  812. std::cout << "\n===== DEPENDENT INTERLEAVED =====\n";
  813. mpcio.reset_stats();
  814. tio.reset_lamport();
  815. T three;
  816. three.set(3*tio.player()); // Sets the shared value to 3
  817. // Follow the linked list and whenever A[addr]=val, set
  818. // A[addr+3]=val+3
  819. cur_index = prev_index;
  820. for (int i=0;i<items;++i) {
  821. T next_index = A[cur_index];
  822. A[cur_index+three] = next_index+three;
  823. cur_index = next_index;
  824. }
  825. tio.sync_lamport();
  826. mpcio.dump_stats(std::cout);
  827. std::cout << "\n";
  828. mpcio.reset_stats();
  829. tio.reset_lamport();
  830. if (depth <= 30) {
  831. auto check = A.reconstruct();
  832. auto head = A.reconstruct(prev_index);
  833. if (tio.player() == 0) {
  834. int width = (depth+3)/4;
  835. printf("Head of linked list: %0*lx\n\n", width,
  836. head.share() & mask);
  837. std::cout << "Non-zero reconstructed database entries:\n";
  838. for (address_t i=0;i<size;++i) {
  839. value_t share = check[i].share() & mask;
  840. if (share) printf("%0*x: %0*lx\n", width, i, width, share);
  841. }
  842. }
  843. }
  844. });
  845. }
  846. static void cdpf_test(MPCIO &mpcio,
  847. const PRACOptions &opts, char **args)
  848. {
  849. value_t query, target;
  850. int iters = 1;
  851. arc4random_buf(&query, sizeof(query));
  852. arc4random_buf(&target, sizeof(target));
  853. if (*args) {
  854. query = strtoull(*args, NULL, 16);
  855. ++args;
  856. }
  857. if (*args) {
  858. target = strtoull(*args, NULL, 16);
  859. ++args;
  860. }
  861. if (*args) {
  862. iters = atoi(*args);
  863. ++args;
  864. }
  865. int num_threads = opts.num_threads;
  866. boost::asio::thread_pool pool(num_threads);
  867. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  868. boost::asio::post(pool, [&mpcio, thread_num, query, target, iters] {
  869. MPCTIO tio(mpcio, thread_num);
  870. run_coroutines(tio, [&tio, query, target, iters] (yield_t &yield) {
  871. size_t &aes_ops = tio.aes_ops();
  872. for (int i=0;i<iters;++i) {
  873. if (tio.player() == 2) {
  874. tio.cdpf(yield);
  875. auto [ dpf0, dpf1 ] = CDPF::generate(target, aes_ops);
  876. DPFnode leaf0 = dpf0.leaf(query, aes_ops);
  877. DPFnode leaf1 = dpf1.leaf(query, aes_ops);
  878. printf("DPFXOR_{%016lx}(%016lx} = ", target, query);
  879. dump_node(leaf0 ^ leaf1);
  880. } else {
  881. CDPF dpf = tio.cdpf(yield);
  882. printf("ashare = %016lX\nxshare = %016lX\n",
  883. dpf.as_target.ashare, dpf.xs_target.xshare);
  884. DPFnode leaf = dpf.leaf(query, aes_ops);
  885. printf("DPF(%016lx) = ", query);
  886. dump_node(leaf);
  887. if (tio.player() == 1) {
  888. tio.iostream_peer() << leaf;
  889. } else {
  890. DPFnode peerleaf;
  891. tio.iostream_peer() >> peerleaf;
  892. printf("XOR = ");
  893. dump_node(leaf ^ peerleaf);
  894. }
  895. }
  896. }
  897. });
  898. });
  899. }
  900. pool.join();
  901. }
  902. static int compare_test_one(MPCTIO &tio, yield_t &yield,
  903. value_t target, value_t x)
  904. {
  905. int player = tio.player();
  906. size_t &aes_ops = tio.aes_ops();
  907. int res = 1;
  908. if (player == 2) {
  909. // Create a CDPF pair with the given target
  910. auto [dpf0, dpf1] = CDPF::generate(target, aes_ops);
  911. // Send it and a share of x to the computational parties
  912. RegAS x0, x1;
  913. x0.randomize();
  914. x1.set(x-x0.share());
  915. tio.iostream_p0() << dpf0 << x0;
  916. tio.iostream_p1() << dpf1 << x1;
  917. } else {
  918. CDPF dpf;
  919. RegAS xsh;
  920. tio.iostream_server() >> dpf >> xsh;
  921. auto [lt, eq, gt] = dpf.compare(tio, yield, xsh, aes_ops);
  922. RegBS eeq = dpf.is_zero(tio, yield, xsh, aes_ops);
  923. printf("%016lx %016lx %d %d %d %d ", target, x, lt.bshare,
  924. eq.bshare, gt.bshare, eeq.bshare);
  925. // Check the answer
  926. if (player == 1) {
  927. tio.iostream_peer() << xsh << lt << eq << gt << eeq;
  928. } else {
  929. RegAS peer_xsh;
  930. RegBS peer_lt, peer_eq, peer_gt, peer_eeq;
  931. tio.iostream_peer() >> peer_xsh >> peer_lt >> peer_eq >>
  932. peer_gt >> peer_eeq;
  933. lt ^= peer_lt;
  934. eq ^= peer_eq;
  935. gt ^= peer_gt;
  936. eeq ^= peer_eeq;
  937. xsh += peer_xsh;
  938. int lti = int(lt.bshare);
  939. int eqi = int(eq.bshare);
  940. int gti = int(gt.bshare);
  941. int eeqi = int(eeq.bshare);
  942. x = xsh.share();
  943. printf(": %d %d %d %d ", lti, eqi, gti, eeqi);
  944. bool signbit = (x >> 63);
  945. if (lti + eqi + gti != 1 || eqi != eeqi) {
  946. printf("INCONSISTENT");
  947. res = 0;
  948. } else if (x == 0 && eqi) {
  949. printf("=");
  950. } else if (!signbit && gti) {
  951. printf(">");
  952. } else if (signbit && lti) {
  953. printf("<");
  954. } else {
  955. printf("INCORRECT");
  956. res = 0;
  957. }
  958. }
  959. printf("\n");
  960. }
  961. return res;
  962. }
  963. static int compare_test_target(MPCTIO &tio, yield_t &yield,
  964. value_t target, value_t x)
  965. {
  966. int res = 1;
  967. res &= compare_test_one(tio, yield, target, x);
  968. res &= compare_test_one(tio, yield, target, 0);
  969. res &= compare_test_one(tio, yield, target, 1);
  970. res &= compare_test_one(tio, yield, target, 15);
  971. res &= compare_test_one(tio, yield, target, 16);
  972. res &= compare_test_one(tio, yield, target, 17);
  973. res &= compare_test_one(tio, yield, target, -1);
  974. res &= compare_test_one(tio, yield, target, -15);
  975. res &= compare_test_one(tio, yield, target, -16);
  976. res &= compare_test_one(tio, yield, target, -17);
  977. res &= compare_test_one(tio, yield, target, (value_t(1)<<63));
  978. res &= compare_test_one(tio, yield, target, (value_t(1)<<63)+1);
  979. res &= compare_test_one(tio, yield, target, (value_t(1)<<63)-1);
  980. return res;
  981. }
  982. static void compare_test(MPCIO &mpcio,
  983. const PRACOptions &opts, char **args)
  984. {
  985. value_t target, x;
  986. arc4random_buf(&target, sizeof(target));
  987. arc4random_buf(&x, sizeof(x));
  988. if (*args) {
  989. target = strtoull(*args, NULL, 16);
  990. ++args;
  991. }
  992. if (*args) {
  993. x = strtoull(*args, NULL, 16);
  994. ++args;
  995. }
  996. int num_threads = opts.num_threads;
  997. boost::asio::thread_pool pool(num_threads);
  998. for (int thread_num = 0; thread_num < num_threads; ++thread_num) {
  999. boost::asio::post(pool, [&mpcio, thread_num, target, x] {
  1000. MPCTIO tio(mpcio, thread_num);
  1001. run_coroutines(tio, [&tio, target, x] (yield_t &yield) {
  1002. int res = 1;
  1003. res &= compare_test_target(tio, yield, target, x);
  1004. res &= compare_test_target(tio, yield, 0, x);
  1005. res &= compare_test_target(tio, yield, 1, x);
  1006. res &= compare_test_target(tio, yield, 15, x);
  1007. res &= compare_test_target(tio, yield, 16, x);
  1008. res &= compare_test_target(tio, yield, 17, x);
  1009. res &= compare_test_target(tio, yield, -1, x);
  1010. res &= compare_test_target(tio, yield, -15, x);
  1011. res &= compare_test_target(tio, yield, -16, x);
  1012. res &= compare_test_target(tio, yield, -17, x);
  1013. res &= compare_test_target(tio, yield, (value_t(1)<<63), x);
  1014. res &= compare_test_target(tio, yield, (value_t(1)<<63)+1, x);
  1015. res &= compare_test_target(tio, yield, (value_t(1)<<63)-1, x);
  1016. if (tio.player() == 0) {
  1017. if (res == 1) {
  1018. printf("All tests passed!\n");
  1019. } else {
  1020. printf("TEST FAILURES\n");
  1021. }
  1022. }
  1023. });
  1024. });
  1025. }
  1026. pool.join();
  1027. }
  1028. static void sort_test(MPCIO &mpcio,
  1029. const PRACOptions &opts, char **args)
  1030. {
  1031. nbits_t depth=6;
  1032. if (*args) {
  1033. depth = atoi(*args);
  1034. ++args;
  1035. }
  1036. address_t len = (1<<depth);
  1037. if (*args) {
  1038. len = atoi(*args);
  1039. ++args;
  1040. }
  1041. MPCTIO tio(mpcio, 0, opts.num_threads);
  1042. run_coroutines(tio, [&tio, depth, len] (yield_t &yield) {
  1043. address_t size = address_t(1)<<depth;
  1044. // size_t &aes_ops = tio.aes_ops();
  1045. Duoram<RegAS> oram(tio.player(), size);
  1046. auto A = oram.flat(tio, yield);
  1047. A.explicitonly(true);
  1048. // Initialize the memory to random values in parallel
  1049. std::vector<coro_t> coroutines;
  1050. for (address_t i=0; i<size; ++i) {
  1051. coroutines.emplace_back(
  1052. [&A, i](yield_t &yield) {
  1053. auto Acoro = A.context(yield);
  1054. RegAS v;
  1055. v.randomize(62);
  1056. Acoro[i] += v;
  1057. });
  1058. }
  1059. run_coroutines(yield, coroutines);
  1060. A.bitonic_sort(0, len);
  1061. if (depth <= 10) {
  1062. oram.dump();
  1063. }
  1064. auto check = A.reconstruct();
  1065. bool fail = false;
  1066. if (tio.player() == 0) {
  1067. for (address_t i=0;i<size;++i) {
  1068. if (depth <= 10) {
  1069. printf("%04x %016lx\n", i, check[i].share());
  1070. }
  1071. if (i>0 && i<len &&
  1072. check[i].share() < check[i-1].share()) {
  1073. fail = true;
  1074. }
  1075. }
  1076. if (fail) {
  1077. printf("FAIL\n");
  1078. } else {
  1079. printf("PASS\n");
  1080. }
  1081. }
  1082. });
  1083. }
  1084. static void pad_test(MPCIO &mpcio,
  1085. const PRACOptions &opts, char **args)
  1086. {
  1087. nbits_t depth=6;
  1088. if (*args) {
  1089. depth = atoi(*args);
  1090. ++args;
  1091. }
  1092. address_t len = (1<<depth);
  1093. if (*args) {
  1094. len = atoi(*args);
  1095. ++args;
  1096. }
  1097. MPCTIO tio(mpcio, 0, opts.num_threads);
  1098. run_coroutines(tio, [&mpcio, &tio, depth, len] (yield_t &yield) {
  1099. int player = tio.player();
  1100. Duoram<RegAS> oram(player, len);
  1101. auto A = oram.flat(tio, yield);
  1102. // Initialize the ORAM in explicit mode
  1103. A.explicitonly(true);
  1104. for (address_t i=0; i<len; ++i) {
  1105. RegAS v;
  1106. v.set((player*0xffff+1)*i);
  1107. A[i] = v;
  1108. }
  1109. A.explicitonly(false);
  1110. // Obliviously add 0 to A[0], which reblinds the whole database
  1111. RegAS z;
  1112. A[z] += z;
  1113. auto check = A.reconstruct();
  1114. if (player == 0) {
  1115. for (address_t i=0;i<len;++i) {
  1116. if (depth <= 10) {
  1117. printf("%04x %016lx\n", i, check[i].share());
  1118. }
  1119. }
  1120. printf("\n");
  1121. }
  1122. address_t maxsize = address_t(1)<<depth;
  1123. Duoram<RegAS>::Pad P(A, tio, yield, maxsize);
  1124. for (address_t i=0; i<maxsize; ++i) {
  1125. RegAS v = P[i];
  1126. if (depth <= 10) {
  1127. value_t vval = mpc_reconstruct(tio, yield, v);
  1128. printf("%04x %016lx %016lx\n", i, v.share(), vval);
  1129. }
  1130. }
  1131. printf("\n");
  1132. for (address_t i=0; i<maxsize; ++i) {
  1133. value_t offset = 0xdeadbeef;
  1134. if (player) {
  1135. offset = -offset;
  1136. }
  1137. RegAS ind;
  1138. ind.set(player*i+offset);
  1139. RegAS v = P[ind];
  1140. if (depth <= 10) {
  1141. value_t vval = mpc_reconstruct(tio, yield, v);
  1142. printf("%04x %016lx %016lx\n", i, v.share(), vval);
  1143. }
  1144. }
  1145. printf("\n");
  1146. });
  1147. }
  1148. static void bsearch_test(MPCIO &mpcio,
  1149. const PRACOptions &opts, char **args, bool basic)
  1150. {
  1151. value_t target;
  1152. arc4random_buf(&target, sizeof(target));
  1153. target >>= 1;
  1154. nbits_t depth=6;
  1155. if (*args) {
  1156. depth = atoi(*args);
  1157. ++args;
  1158. }
  1159. address_t len = (1<<depth);
  1160. if (*args) {
  1161. len = atoi(*args);
  1162. ++args;
  1163. }
  1164. if (*args) {
  1165. target = strtoull(*args, NULL, 16);
  1166. ++args;
  1167. }
  1168. MPCTIO tio(mpcio, 0, opts.num_threads);
  1169. run_coroutines(tio, [&tio, &mpcio, depth, len, target, basic] (yield_t &yield) {
  1170. RegAS tshare;
  1171. std::cout << "\n===== SETUP =====\n";
  1172. if (tio.player() == 2) {
  1173. // Send shares of the target to the computational
  1174. // players
  1175. RegAS tshare0, tshare1;
  1176. tshare0.randomize();
  1177. tshare1.set(target-tshare0.share());
  1178. tio.iostream_p0() << tshare0;
  1179. tio.iostream_p1() << tshare1;
  1180. printf("Using target = %016lx\n", target);
  1181. yield();
  1182. } else {
  1183. // Get the share of the target
  1184. tio.iostream_server() >> tshare;
  1185. }
  1186. tio.sync_lamport();
  1187. mpcio.dump_stats(std::cout);
  1188. std::cout << "\n===== SORT RANDOM DATABASE =====\n";
  1189. mpcio.reset_stats();
  1190. tio.reset_lamport();
  1191. // Create a random database and sort it
  1192. // size_t &aes_ops = tio.aes_ops();
  1193. Duoram<RegAS> oram(tio.player(), len);
  1194. auto A = oram.flat(tio, yield);
  1195. A.explicitonly(true);
  1196. // Initialize the memory to random values in parallel
  1197. std::vector<coro_t> coroutines;
  1198. for (address_t i=0; i<len; ++i) {
  1199. coroutines.emplace_back(
  1200. [&A, i](yield_t &yield) {
  1201. auto Acoro = A.context(yield);
  1202. RegAS v;
  1203. v.randomize(62);
  1204. Acoro[i] += v;
  1205. });
  1206. }
  1207. run_coroutines(yield, coroutines);
  1208. A.bitonic_sort(0, len);
  1209. A.explicitonly(false);
  1210. tio.sync_lamport();
  1211. mpcio.dump_stats(std::cout);
  1212. std::cout << "\n===== BINARY SEARCH =====\n";
  1213. mpcio.reset_stats();
  1214. tio.reset_lamport();
  1215. // Binary search for the target
  1216. value_t checkindex;
  1217. if (basic) {
  1218. RegAS tindex = A.basic_binary_search(tshare);
  1219. checkindex = mpc_reconstruct(tio, yield, tindex);
  1220. } else {
  1221. RegXS tindex = A.binary_search(tshare);
  1222. checkindex = mpc_reconstruct(tio, yield, tindex);
  1223. }
  1224. tio.sync_lamport();
  1225. mpcio.dump_stats(std::cout);
  1226. std::cout << "\n===== CHECK ANSWER =====\n";
  1227. mpcio.reset_stats();
  1228. tio.reset_lamport();
  1229. // Check the answer
  1230. size_t size = size_t(1) << depth;
  1231. value_t checktarget = mpc_reconstruct(tio, yield, tshare);
  1232. auto check = A.reconstruct();
  1233. bool fail = false;
  1234. if (tio.player() == 0) {
  1235. for (address_t i=0;i<len;++i) {
  1236. if (depth <= 10) {
  1237. printf("%c%04x %016lx\n",
  1238. (i == checkindex ? '*' : ' '),
  1239. i, check[i].share());
  1240. }
  1241. if (i>0 && i<len &&
  1242. check[i].share() < check[i-1].share()) {
  1243. fail = true;
  1244. }
  1245. if (i == checkindex) {
  1246. // check[i] should be >= target, and check[i-1]
  1247. // should be < target
  1248. if ((i < len && check[i].share() < checktarget) ||
  1249. (i > 0 && check[i-1].share() >= checktarget)) {
  1250. fail = true;
  1251. }
  1252. }
  1253. }
  1254. if (checkindex == len && check[len-1].share() >= checktarget) {
  1255. fail = true;
  1256. }
  1257. printf("Target = %016lx\n", checktarget);
  1258. printf("Found index = %02lx\n", checkindex);
  1259. if (checkindex > size) {
  1260. fail = true;
  1261. }
  1262. if (fail) {
  1263. printf("FAIL\n");
  1264. } else {
  1265. printf("PASS\n");
  1266. }
  1267. }
  1268. });
  1269. }
  1270. template <typename T>
  1271. static void related(MPCIO &mpcio,
  1272. const PRACOptions &opts, char **args)
  1273. {
  1274. nbits_t depth = 5;
  1275. // The depth of the (complete) binary tree
  1276. if (*args) {
  1277. depth = atoi(*args);
  1278. ++args;
  1279. }
  1280. // The layer at which to choose a random parent node (and its two
  1281. // children along with it)
  1282. nbits_t layer = depth-1;
  1283. if (*args) {
  1284. layer = atoi(*args);
  1285. ++args;
  1286. }
  1287. assert(layer < depth);
  1288. MPCTIO tio(mpcio, 0, opts.num_threads);
  1289. run_coroutines(tio, [&mpcio, &tio, depth, layer] (yield_t &yield) {
  1290. size_t size = size_t(1)<<(depth+1);
  1291. Duoram<T> oram(tio.player(), size);
  1292. auto A = oram.flat(tio, yield);
  1293. // Initialize A with words with sequential top and bottom halves
  1294. // (just so we can more easily eyeball the right answers)
  1295. A.init([] (size_t i) { return i * 0x100000001; } );
  1296. // We use this layout for the tree:
  1297. // A[0] is unused
  1298. // A[1] is the root (layer 0)
  1299. // A[2..3] is layer 1
  1300. // A[4..7] is layer 2
  1301. // ...
  1302. // A[(1<<j)..((2<<j)-1)] is layer j
  1303. //
  1304. // So the parent of x is at location (x/2) and the children of x
  1305. // are at locations 2*x and 2*x+1
  1306. // Pick a random index _within_ the given layer (i.e., the
  1307. // offset from the beginning of the layer, not the absolute
  1308. // location in A)
  1309. RegXS idx;
  1310. idx.randomize(layer);
  1311. // Create the OblivIndex. RegXS is the type of the common index
  1312. // (idx), 3 is the maximum number of related updates to support
  1313. // (which equals the width of the underlying RDPF, currently
  1314. // maximum 5), layer is the depth of the underlying RDPF (the
  1315. // bit length of idx).
  1316. typename Duoram<T>::template OblivIndex<RegXS,3> oidx(tio, yield, idx, layer);
  1317. // This is the (known) layer containing the (unknown) parent
  1318. // node
  1319. typename Duoram<T>::Flat P(A, tio, yield, 1<<layer, 1<<layer);
  1320. // This is the layer below that one, containing all possible
  1321. // children
  1322. typename Duoram<T>::Flat C(A, tio, yield, 2<<layer, 2<<layer);
  1323. // These are the subsets of C containing the left children and
  1324. // the right children respectively
  1325. typename Duoram<T>::Stride L(C, tio, yield, 0, 2);
  1326. typename Duoram<T>::Stride R(C, tio, yield, 1, 2);
  1327. T parent, left, right;
  1328. // Do three related reads. In this version, only one DPF will
  1329. // be used, but it will still be _evaluated_ three times.
  1330. parent = P[oidx];
  1331. left = L[oidx];
  1332. right = R[oidx];
  1333. // The operation is just a simple rotation: the value in the
  1334. // parent moves to the left child, the left child moves to the
  1335. // right child, and the right child becomes the parent
  1336. // Do three related updates. As above, only one (wide) DPF will
  1337. // be used (the same one as for the reads in fact), but it will
  1338. // still be _evaluated_ three more times.
  1339. P[oidx] += right-parent;
  1340. L[oidx] += parent-left;
  1341. R[oidx] += left-right;
  1342. // Check the answer
  1343. auto check = A.reconstruct();
  1344. if (depth <= 10) {
  1345. oram.dump();
  1346. if (tio.player() == 0) {
  1347. for (address_t i=0;i<size;++i) {
  1348. printf("%04x %016lx\n", i, check[i].share());
  1349. }
  1350. }
  1351. }
  1352. value_t pval = mpc_reconstruct(tio, yield, parent);
  1353. value_t lval = mpc_reconstruct(tio, yield, left);
  1354. value_t rval = mpc_reconstruct(tio, yield, right);
  1355. printf("parent = %016lx\nleft = %016lx\nright = %016lx\n",
  1356. pval, lval, rval);
  1357. });
  1358. }
  1359. template <typename T>
  1360. static void path(MPCIO &mpcio,
  1361. const PRACOptions &opts, char **args)
  1362. {
  1363. nbits_t depth = 5;
  1364. // The depth of the (complete) binary tree
  1365. if (*args) {
  1366. depth = atoi(*args);
  1367. ++args;
  1368. }
  1369. // The target node
  1370. size_t target_node = 3 << (depth-1);
  1371. if (*args) {
  1372. target_node = atoi(*args);
  1373. ++args;
  1374. }
  1375. MPCTIO tio(mpcio, 0, opts.num_threads);
  1376. run_coroutines(tio, [&mpcio, &tio, depth, target_node] (yield_t &yield) {
  1377. size_t size = size_t(1)<<(depth+1);
  1378. Duoram<T> oram(tio.player(), size);
  1379. auto A = oram.flat(tio, yield);
  1380. // Initialize A with words with sequential top and bottom halves
  1381. // (just so we can more easily eyeball the right answers)
  1382. A.init([] (size_t i) { return i * 0x100000001; } );
  1383. // We use this layout for the tree:
  1384. // A[0] is unused
  1385. // A[1] is the root (layer 0)
  1386. // A[2..3] is layer 1
  1387. // A[4..7] is layer 2
  1388. // ...
  1389. // A[(1<<j)..((2<<j)-1)] is layer j
  1390. //
  1391. // So the parent of x is at location (x/2) and the children of x
  1392. // are at locations 2*x and 2*x+1
  1393. // Create a Path from the root to the target node
  1394. typename Duoram<T>::Path P(A, tio, yield, target_node);
  1395. // Re-initialize that path to something recognizable
  1396. P.init([] (size_t i) { return 0xff + i * 0x1000000010000; } );
  1397. // ORAM update along that path
  1398. RegXS idx;
  1399. idx.set(tio.player() * arc4random_uniform(P.size()));
  1400. T val;
  1401. val.set(tio.player() * 0xaaaa00000000);
  1402. P[idx] += val;
  1403. // Binary search along that path
  1404. T lookup;
  1405. lookup.set(tio.player() * 0x3000000000000);
  1406. RegXS foundidx = P.binary_search(lookup);
  1407. // Check the answer
  1408. auto check = A.reconstruct();
  1409. if (depth <= 10) {
  1410. oram.dump();
  1411. if (tio.player() == 0) {
  1412. for (address_t i=0;i<size;++i) {
  1413. printf("%04x %016lx\n", i, check[i].share());
  1414. }
  1415. }
  1416. }
  1417. value_t found = mpc_reconstruct(tio, yield, foundidx);
  1418. printf("foundidx = %lu\n", found);
  1419. });
  1420. }
  1421. void online_main(MPCIO &mpcio, const PRACOptions &opts, char **args)
  1422. {
  1423. MPCTIO tio(mpcio, 0);
  1424. if (!*args) {
  1425. std::cerr << "Mode is required as the first argument when not preprocessing.\n";
  1426. return;
  1427. } else if (!strcmp(*args, "test")) {
  1428. ++args;
  1429. online_test(mpcio, opts, args);
  1430. } else if (!strcmp(*args, "lamporttest")) {
  1431. ++args;
  1432. lamport_test(mpcio, opts, args);
  1433. } else if (!strcmp(*args, "rdpftest")) {
  1434. ++args;
  1435. rdpf_test<1>(mpcio, opts, args, false);
  1436. } else if (!strcmp(*args, "rdpftest2")) {
  1437. ++args;
  1438. rdpf_test<2>(mpcio, opts, args, false);
  1439. } else if (!strcmp(*args, "rdpftest3")) {
  1440. ++args;
  1441. rdpf_test<3>(mpcio, opts, args, false);
  1442. } else if (!strcmp(*args, "rdpftest4")) {
  1443. ++args;
  1444. rdpf_test<4>(mpcio, opts, args, false);
  1445. } else if (!strcmp(*args, "rdpftest5")) {
  1446. ++args;
  1447. rdpf_test<5>(mpcio, opts, args, false);
  1448. } else if (!strcmp(*args, "irdpftest")) {
  1449. ++args;
  1450. rdpf_test<1>(mpcio, opts, args, true);
  1451. } else if (!strcmp(*args, "irdpftest2")) {
  1452. ++args;
  1453. rdpf_test<2>(mpcio, opts, args, true);
  1454. } else if (!strcmp(*args, "irdpftest3")) {
  1455. ++args;
  1456. rdpf_test<3>(mpcio, opts, args, true);
  1457. } else if (!strcmp(*args, "irdpftest4")) {
  1458. ++args;
  1459. rdpf_test<4>(mpcio, opts, args, true);
  1460. } else if (!strcmp(*args, "irdpftest5")) {
  1461. ++args;
  1462. rdpf_test<5>(mpcio, opts, args, true);
  1463. } else if (!strcmp(*args, "rdpftime")) {
  1464. ++args;
  1465. rdpf_timing(mpcio, opts, args);
  1466. } else if (!strcmp(*args, "evaltime")) {
  1467. ++args;
  1468. rdpfeval_timing(mpcio, opts, args);
  1469. } else if (!strcmp(*args, "parevaltime")) {
  1470. ++args;
  1471. par_rdpfeval_timing(mpcio, opts, args);
  1472. } else if (!strcmp(*args, "tupletime")) {
  1473. ++args;
  1474. tupleeval_timing(mpcio, opts, args);
  1475. } else if (!strcmp(*args, "partupletime")) {
  1476. ++args;
  1477. par_tupleeval_timing(mpcio, opts, args);
  1478. } else if (!strcmp(*args, "duotest")) {
  1479. ++args;
  1480. if (opts.use_xor_db) {
  1481. duoram_test<RegXS>(mpcio, opts, args);
  1482. } else {
  1483. duoram_test<RegAS>(mpcio, opts, args);
  1484. }
  1485. } else if (!strcmp(*args, "cdpftest")) {
  1486. ++args;
  1487. cdpf_test(mpcio, opts, args);
  1488. } else if (!strcmp(*args, "cmptest")) {
  1489. ++args;
  1490. compare_test(mpcio, opts, args);
  1491. } else if (!strcmp(*args, "sorttest")) {
  1492. ++args;
  1493. sort_test(mpcio, opts, args);
  1494. } else if (!strcmp(*args, "padtest")) {
  1495. ++args;
  1496. pad_test(mpcio, opts, args);
  1497. } else if (!strcmp(*args, "bbsearch")) {
  1498. ++args;
  1499. bsearch_test(mpcio, opts, args, true);
  1500. } else if (!strcmp(*args, "bsearch")) {
  1501. ++args;
  1502. bsearch_test(mpcio, opts, args, false);
  1503. } else if (!strcmp(*args, "duoram")) {
  1504. ++args;
  1505. if (opts.use_xor_db) {
  1506. duoram<RegXS>(mpcio, opts, args);
  1507. } else {
  1508. duoram<RegAS>(mpcio, opts, args);
  1509. }
  1510. } else if (!strcmp(*args, "related")) {
  1511. ++args;
  1512. if (opts.use_xor_db) {
  1513. related<RegXS>(mpcio, opts, args);
  1514. } else {
  1515. related<RegAS>(mpcio, opts, args);
  1516. }
  1517. } else if (!strcmp(*args, "path")) {
  1518. ++args;
  1519. path<RegAS>(mpcio, opts, args);
  1520. } else if (!strcmp(*args, "cell")) {
  1521. ++args;
  1522. cell(mpcio, opts, args);
  1523. } else if (!strcmp(*args, "bst")) {
  1524. ++args;
  1525. bst(mpcio, opts, args);
  1526. } else if (!strcmp(*args, "avl")) {
  1527. ++args;
  1528. avl(mpcio, opts, args);
  1529. } else if (!strcmp(*args, "avl_tests")) {
  1530. ++args;
  1531. avl_tests(mpcio, opts, args);
  1532. } else {
  1533. std::cerr << "Unknown mode " << *args << "\n";
  1534. }
  1535. }