avl.cpp 99 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726
  1. #include <functional>
  2. #include "avl.hpp"
  3. void print_green(std::string line) {
  4. printf("%s%s%s", KGRN, line.c_str(), KNRM);
  5. }
  6. void print_red(std::string line) {
  7. printf("%s%s%s", KRED, line.c_str(), KNRM);
  8. }
  9. // Pretty-print a reconstructed BST, rooted at node. is_left_child and
  10. // is_right_child indicate whether node is a left or right child of its
  11. // parent. They cannot both be true, but the root of the tree has both
  12. // of them false.
  13. void AVL::pretty_print(const std::vector<Node> &R, value_t node,
  14. const std::string &prefix = "", bool is_left_child = false,
  15. bool is_right_child = false)
  16. {
  17. if (node == 0) {
  18. // NULL pointer
  19. if (is_left_child) {
  20. printf("%s\xE2\x95\xA7\n", prefix.c_str()); // ╧
  21. } else if (is_right_child) {
  22. printf("%s\xE2\x95\xA4\n", prefix.c_str()); // ╤
  23. } else {
  24. printf("%s\xE2\x95\xA2\n", prefix.c_str()); // ╢
  25. }
  26. return;
  27. }
  28. const Node &n = R[node];
  29. value_t left_ptr = getAVLLeftPtr(n.pointers).xshare;
  30. value_t right_ptr = getAVLRightPtr(n.pointers).xshare;
  31. std::string rightprefix(prefix), leftprefix(prefix),
  32. nodeprefix(prefix);
  33. if (is_left_child) {
  34. rightprefix.append("\xE2\x94\x82"); // │
  35. leftprefix.append(" ");
  36. nodeprefix.append("\xE2\x94\x94"); // └
  37. } else if (is_right_child) {
  38. rightprefix.append(" ");
  39. leftprefix.append("\xE2\x94\x82"); // │
  40. nodeprefix.append("\xE2\x94\x8C"); // ┌
  41. } else {
  42. rightprefix.append(" ");
  43. leftprefix.append(" ");
  44. nodeprefix.append("\xE2\x94\x80"); // ─
  45. }
  46. pretty_print(R, right_ptr, rightprefix, false, true);
  47. printf("%s\xE2\x94\xA4", nodeprefix.c_str()); // ┤
  48. dumpAVL(n);
  49. printf("\n");
  50. pretty_print(R, left_ptr, leftprefix, true, false);
  51. }
  52. void AVL::print_oram(MPCTIO &tio, yield_t &yield) {
  53. auto A = oram->flat(tio, yield);
  54. auto R = A.reconstruct();
  55. for(size_t i=0;i<R.size();++i) {
  56. printf("\n%04lx ", i);
  57. R[i].dump();
  58. }
  59. printf("\n");
  60. }
  61. void AVL::pretty_print(MPCTIO &tio, yield_t &yield) {
  62. RegXS peer_root;
  63. RegXS reconstructed_root = root;
  64. if (tio.player() == 1) {
  65. tio.queue_peer(&root, sizeof(root));
  66. } else {
  67. RegXS peer_root;
  68. tio.recv_peer(&peer_root, sizeof(peer_root));
  69. reconstructed_root += peer_root;
  70. }
  71. auto A = oram->flat(tio, yield);
  72. auto R = A.reconstruct();
  73. if(tio.player()==0) {
  74. pretty_print(R, reconstructed_root.xshare);
  75. }
  76. }
  77. // Check the BST invariant of the tree (that all keys to the left are
  78. // less than or equal to this key, all keys to the right are strictly
  79. // greater, and this is true recursively). Returns a
  80. // tuple<bool,address_t>, where the bool says whether the BST invariant
  81. // holds, and the address_t is the height of the tree (which will be
  82. // useful later when we check AVL trees).
  83. std::tuple<bool, bool, address_t> AVL::check_avl(const std::vector<Node> &R,
  84. value_t node, value_t min_key = 0, value_t max_key = ~0)
  85. {
  86. if (node == 0) {
  87. return { true, true, 0 };
  88. }
  89. const Node &n = R[node];
  90. value_t key = n.key.ashare;
  91. value_t left_ptr = getAVLLeftPtr(n.pointers).xshare;
  92. value_t right_ptr = getAVLRightPtr(n.pointers).xshare;
  93. auto [leftok, leftavlok, leftheight ] = check_avl(R, left_ptr, min_key, key);
  94. auto [rightok, rightavlok, rightheight ] = check_avl(R, right_ptr, key+1, max_key);
  95. address_t height = leftheight;
  96. if (rightheight > height) {
  97. height = rightheight;
  98. }
  99. height += 1;
  100. int heightgap = leftheight - rightheight;
  101. bool avlok = (abs(heightgap)<2);
  102. //printf("node = %ld, leftok = %d, rightok = %d\n", node, leftok, rightok);
  103. return { leftok && rightok && key >= min_key && key <= max_key,
  104. avlok && leftavlok && rightavlok, height};
  105. }
  106. void AVL::check_avl(MPCTIO &tio, yield_t &yield) {
  107. auto A = oram->flat(tio, yield);
  108. auto R = A.reconstruct();
  109. RegXS rec_root = this->root;
  110. if (tio.player() == 1) {
  111. tio.queue_peer(&(this->root), sizeof(this->root));
  112. } else {
  113. RegXS peer_root;
  114. tio.recv_peer(&peer_root, sizeof(peer_root));
  115. rec_root+= peer_root;
  116. }
  117. if (tio.player() == 0) {
  118. auto [ bst_ok, avl_ok, height ] = check_avl(R, rec_root.xshare);
  119. printf("BST structure %s\nAVL structure %s\nTree height = %u\n",
  120. bst_ok ? "ok" : "NOT OK", avl_ok ? "ok" : "NOT OK", height);
  121. }
  122. }
  123. void AVL::initialize(int num_players, size_t size) {
  124. this->MAX_SIZE = size;
  125. oram = new Duoram<Node>(num_players, size);
  126. }
  127. /*
  128. Rotate: (gp = grandparent (if exists), p = parent, c = child)
  129. This rotates the p -> c link.
  130. gp gp
  131. \ \
  132. p --- Left rotate ---> c
  133. \ /
  134. c p
  135. gp gp
  136. \ \
  137. p --- Right rotate ---> c
  138. / \
  139. c p
  140. */
  141. void AVL::rotate(MPCTIO &tio, yield_t &yield, RegXS &gp_pointers, RegXS p_ptr,
  142. RegXS &p_pointers, RegXS c_ptr, RegXS &c_pointers, RegBS dir_gpp,
  143. RegBS dir_pc, RegBS isReal, RegBS F_gp) {
  144. bool player0 = tio.player()==0;
  145. RegXS gp_left = getAVLLeftPtr(gp_pointers);
  146. RegXS gp_right = getAVLRightPtr(gp_pointers);
  147. RegXS p_left = getAVLLeftPtr(p_pointers);
  148. RegXS p_right = getAVLRightPtr(p_pointers);
  149. RegXS c_left = getAVLLeftPtr(c_pointers);
  150. RegXS c_right = getAVLRightPtr(c_pointers);
  151. RegXS ptr_upd;
  152. // F_gpp: Flag to update gp -> p link, F_pc: Flag to update p -> c link
  153. RegBS F_gpp, F_pc, F_gppr, F_gppl;
  154. // We care about !F_gp. If !F_gp, then we do the gp->p link updates.
  155. // Otherwise, we do NOT do any updates to gp-> p link;
  156. // since F_gp==1, implies gp does not exist and parent is root.
  157. if(player0)
  158. F_gp^=1;
  159. mpc_and(tio, yield, F_gpp, F_gp, isReal);
  160. // i) gp[dir_gpp] <-- c_ptr
  161. mpc_select(tio, yield, ptr_upd, F_gpp, p_ptr, c_ptr);
  162. mpc_and(tio, yield, F_gppr, F_gpp, dir_gpp);
  163. mpc_select(tio, yield, gp_right, F_gppr, gp_right, ptr_upd);
  164. if(player0)
  165. dir_gpp^=1;
  166. mpc_and(tio, yield, F_gppl, F_gpp, dir_gpp);
  167. mpc_select(tio, yield, gp_left, F_gppl, gp_left, ptr_upd);
  168. setAVLLeftPtr(gp_pointers, gp_left);
  169. setAVLRightPtr(gp_pointers, gp_right);
  170. // ii) p[dir_pc] <-- c[!dir_pc] and iii) c[!dir_pc] <-- p_ptr
  171. RegBS not_dir_pc = dir_pc;
  172. if(player0)
  173. not_dir_pc^=1;
  174. RegXS c_not_dir_pc; //c[!dir_pc]
  175. // ndpc_right: if not_dir_pc is right
  176. // ndpc_left: if not_dir_pc is left
  177. RegBS F_ndpc_right, F_ndpc_left;
  178. mpc_and(tio, yield, F_ndpc_right, isReal, not_dir_pc);
  179. mpc_select(tio, yield, c_not_dir_pc, F_ndpc_right, c_not_dir_pc, c_right, AVL_PTR_SIZE);
  180. // Negating not_dir_pc to handle left case
  181. if(player0)
  182. not_dir_pc^=1;
  183. mpc_and(tio, yield, F_ndpc_left, isReal, not_dir_pc);
  184. mpc_select(tio, yield, c_not_dir_pc, F_ndpc_left, c_not_dir_pc, c_left, AVL_PTR_SIZE);
  185. // Now c_not_dir_pc = c[!dir_pc]
  186. // ii) p[dir_pc] <-- c[!dir_pc]
  187. mpc_select(tio, yield, p_left, F_ndpc_right, p_left, c_not_dir_pc, AVL_PTR_SIZE);
  188. mpc_select(tio, yield, p_right, F_ndpc_left, p_right, c_not_dir_pc, AVL_PTR_SIZE);
  189. setAVLLeftPtr(p_pointers, p_left);
  190. setAVLRightPtr(p_pointers, p_right);
  191. // iii): c[!dir_pc] <-- p_ptr
  192. mpc_select(tio, yield, ptr_upd, isReal, c_not_dir_pc, p_ptr, AVL_PTR_SIZE);
  193. mpc_and(tio, yield, F_pc, dir_pc, isReal);
  194. mpc_select(tio, yield, c_left, F_pc, c_left, ptr_upd, AVL_PTR_SIZE);
  195. if(player0)
  196. dir_pc^=1;
  197. // dir_pc <-- !dir_pc
  198. mpc_and(tio, yield, F_pc, dir_pc, isReal);
  199. mpc_select(tio, yield, c_right, F_pc, c_right, ptr_upd, AVL_PTR_SIZE);
  200. setAVLLeftPtr(c_pointers, c_left);
  201. setAVLRightPtr(c_pointers, c_right);
  202. }
  203. /*
  204. In updateBalanceDel, the position of imbalance, and shift direction for both
  205. cases are inverted, since a bal_upd on a child implies it reduced height.
  206. If F_rs: (bal_upd & right_child)
  207. imbalance, bal_l, balanced, bal_r
  208. And then left shift to get imbalance bit, and new bal_l, bal_r bits
  209. else if F_ls: (bal_upd & left_child)
  210. bal_l, balanced, bal_r, imbalance
  211. And then right shift to get imbalance bit, and new bal_l, bal_r bits
  212. */
  213. std::tuple<RegBS, RegBS, RegBS, RegBS> AVL::updateBalanceDel(MPCTIO &tio, yield_t &yield,
  214. RegBS bal_l, RegBS bal_r, RegBS bal_upd, RegBS child_dir) {
  215. bool player0 = tio.player()==0;
  216. RegBS s0;
  217. RegBS F_rs, F_ls, balanced, imbalance;
  218. /*
  219. bool rec_bal_l, rec_bal_r, rec_bal_upd;
  220. rec_bal_l = reconstruct_RegBS(tio, yield, bal_l);
  221. rec_bal_r = reconstruct_RegBS(tio, yield, bal_r);
  222. rec_bal_upd = reconstruct_RegBS(tio, yield, bal_upd);
  223. printf("In updateBalanceDel, beforeBalance: rec_bal_l = %d, rec_bal_r = %d, rec_bal_upd = %d\n",
  224. rec_bal_l, rec_bal_r, rec_bal_upd);
  225. */
  226. // balanced = is the node currently balanced
  227. balanced = bal_l ^ bal_r;
  228. //F_ls (Flag left shift) <- child_dir & bal_upd
  229. mpc_and(tio, yield, F_ls, child_dir, bal_upd);
  230. if(player0) {
  231. child_dir^=1;
  232. balanced^=1;
  233. }
  234. //F_rs (Flag right shift) <- !child_dir & bal_upd
  235. mpc_and(tio, yield, F_rs, child_dir, bal_upd);
  236. /*
  237. bool rec_F_ls, rec_F_rs;
  238. rec_F_ls = reconstruct_RegBS(tio, yield, F_ls);
  239. rec_F_rs = reconstruct_RegBS(tio, yield, F_rs);
  240. printf("In updateBalanceDel: rec_F_ls = %d, rec_F_rs = %d\n",
  241. rec_F_ls, rec_F_rs);
  242. */
  243. // Left shift if F_ls
  244. mpc_select(tio, yield, imbalance, F_ls, imbalance, bal_l);
  245. mpc_select(tio, yield, bal_l, F_ls, bal_l, balanced);
  246. mpc_select(tio, yield, balanced, F_ls, balanced, bal_r);
  247. mpc_select(tio, yield, bal_r, F_ls, bal_r, s0);
  248. // Right shift if F_rs
  249. mpc_select(tio, yield, imbalance, F_rs, imbalance, bal_r);
  250. mpc_select(tio, yield, bal_r, F_rs, bal_r, balanced);
  251. mpc_select(tio, yield, balanced, F_rs, balanced, bal_l);
  252. mpc_select(tio, yield, bal_l, F_rs, bal_l, s0);
  253. /*
  254. rec_bal_l = reconstruct_RegBS(tio, yield, bal_l);
  255. rec_bal_r = reconstruct_RegBS(tio, yield, bal_r);
  256. rec_bal_upd = reconstruct_RegBS(tio, yield, bal_upd);
  257. printf("In updateBalanceDel, afterBalance: rec_bal_l = %d, rec_bal_r = %d, rec_bal_upd = %d\n",
  258. rec_bal_l, rec_bal_r, rec_bal_upd);
  259. */
  260. // if(bal_upd) and not imbalance bal_upd<-0
  261. RegBS bu0;
  262. if(player0){
  263. imbalance^=1;
  264. }
  265. mpc_and(tio, yield, bu0, bal_upd, imbalance);
  266. mpc_select(tio, yield, bal_upd, bu0, bal_upd, s0);
  267. if(player0){
  268. imbalance^=1;
  269. }
  270. // Any bal_upd, propogates all the way up to root
  271. return {bal_l, bal_r, bal_upd, imbalance};
  272. }
  273. /*
  274. If F_rs: (bal_upd & right_child)
  275. bal_l, balanced, bal_r, imbalance
  276. And then right shift to get imbalance bit, and new bal_l, bal_r bits
  277. else if F_ls: (bal_upd & left_child)
  278. imbalance, bal_l, balanced, bal_r
  279. And then left shift to get imbalance bit, and new bal_l, bal_r bits
  280. */
  281. std::tuple<RegBS, RegBS, RegBS, RegBS> AVL::updateBalanceIns(MPCTIO &tio, yield_t &yield,
  282. RegBS bal_l, RegBS bal_r, RegBS bal_upd, RegBS child_dir) {
  283. bool player0 = tio.player()==0;
  284. RegBS s1, s0;
  285. s1.set(tio.player()==1);
  286. RegBS F_rs, F_ls, balanced, imbalance;
  287. // balanced = is the node currently balanced
  288. balanced = bal_l ^ bal_r;
  289. //F_rs (Flag right shift) <- child_dir & bal_upd
  290. mpc_and(tio, yield, F_rs, child_dir, bal_upd);
  291. if(player0) {
  292. child_dir^=1;
  293. balanced^=1;
  294. }
  295. //F_ls (Flag left shift) <- !child_dir & bal_upd
  296. mpc_and(tio, yield, F_ls, child_dir, bal_upd);
  297. // Right shift if child_dir = 1 & bal_upd = 1
  298. mpc_select(tio, yield, imbalance, F_rs, imbalance, bal_r);
  299. mpc_select(tio, yield, bal_r, F_rs, bal_r, balanced);
  300. mpc_select(tio, yield, balanced, F_rs, balanced, bal_l);
  301. mpc_select(tio, yield, bal_l, F_rs, bal_l, s0);
  302. // Left shift if child_dir = 0 & bal_upd = 1
  303. mpc_select(tio, yield, imbalance, F_ls, imbalance, bal_l);
  304. mpc_select(tio, yield, bal_l, F_ls, bal_l, balanced);
  305. mpc_select(tio, yield, balanced, F_ls, balanced, bal_r);
  306. mpc_select(tio, yield, bal_r, F_ls, bal_r, s0);
  307. // bal_upd' <- bal_upd ^ imbalance
  308. RegBS F_bu0;
  309. mpc_and(tio, yield, F_bu0, bal_upd, balanced);
  310. mpc_select(tio, yield, bal_upd, F_bu0, bal_upd, s0);
  311. mpc_select(tio, yield, bal_upd, imbalance, bal_upd, s0);
  312. return {bal_l, bal_r, bal_upd, imbalance};
  313. }
  314. std::tuple<RegBS, RegBS, RegXS, RegBS> AVL::insert(MPCTIO &tio, yield_t &yield, RegXS ptr,
  315. RegAS insert_key, Duoram<Node>::Flat &A, int TTL, RegBS isDummy, avl_insert_return *ret) {
  316. if(TTL==0) {
  317. RegBS z;
  318. return {z, z, z, z};
  319. }
  320. RegBS isReal = isDummy ^ (tio.player());
  321. Node cnode = A[ptr];
  322. // Compare key
  323. auto [lteq, gt] = compare_keys(tio, yield, cnode.key, insert_key);
  324. // Depending on [lteq, gt] select the next_ptr
  325. RegXS next_ptr;
  326. RegXS left = getAVLLeftPtr(cnode.pointers);
  327. RegXS right = getAVLRightPtr(cnode.pointers);
  328. RegBS bal_l = getLeftBal(cnode.pointers);
  329. RegBS bal_r = getRightBal(cnode.pointers);
  330. /*
  331. size_t rec_left = reconstruct_RegXS(tio, yield, left);
  332. size_t rec_right = reconstruct_RegXS(tio, yield, right);
  333. size_t rec_key = reconstruct_RegAS(tio, yield, cnode.key);
  334. printf("\n\nKey = %ld\n", rec_key);
  335. printf("rec_left = %ld, rec_right = %ld\n", rec_left, rec_right);
  336. */
  337. mpc_select(tio, yield, next_ptr, gt, left, right, AVL_PTR_SIZE);
  338. /*
  339. size_t rec_next_ptr = reconstruct_RegXS(tio, yield, next_ptr);
  340. printf("rec_next_ptr = %ld\n", rec_next_ptr);
  341. */
  342. CDPF dpf = tio.cdpf(yield);
  343. size_t &aes_ops = tio.aes_ops();
  344. // F_z: Check if this is last node on path
  345. RegBS F_z = dpf.is_zero(tio, yield, next_ptr, aes_ops);
  346. RegBS F_i;
  347. // F_i: If this was last node on path (F_z), and isReal insert.
  348. mpc_and(tio, yield, F_i, (isReal), F_z);
  349. isDummy^=F_i;
  350. auto [bal_upd, F_gp, prev_node, prev_dir] = insert(tio, yield,
  351. next_ptr, insert_key, A, TTL-1, isDummy, ret);
  352. /*
  353. rec_bal_upd = reconstruct_RegBS(tio, yield, bal_upd);
  354. rec_F_gp = reconstruct_RegBS(tio, yield, F_gp);
  355. printf("Insert returns: rec_bal_upd = %d, rec_F_gp = %d\n",
  356. rec_bal_upd, rec_F_gp);
  357. size_t rec_ptr = reconstruct_RegXS(tio, yield, ptr);
  358. printf("\nrec_ptr = %ld\n", rec_ptr);
  359. */
  360. // Save insertion pointer and direction
  361. mpc_select(tio, yield, ret->i_node, F_i, ret->i_node, ptr, AVL_PTR_SIZE);
  362. mpc_select(tio, yield, ret->dir_i, F_i, ret->dir_i, gt);
  363. // Update balance
  364. // If we inserted at this level (F_i), bal_upd is set to 1
  365. mpc_or(tio, yield, bal_upd, bal_upd, F_i);
  366. auto [new_bal_l, new_bal_r, new_bal_upd, imbalance] = updateBalanceIns(tio, yield, bal_l, bal_r, bal_upd, gt);
  367. // Store if this insert triggers an imbalance
  368. ret->imbalance ^= imbalance;
  369. // Save grandparent pointer
  370. mpc_select(tio, yield, ret->gp_node, F_gp, ret->gp_node, ptr, AVL_PTR_SIZE);
  371. mpc_select(tio, yield, ret->dir_gpp, F_gp, ret->dir_gpp, gt);
  372. // Save parent pointer
  373. mpc_select(tio, yield, ret->p_node, imbalance, ret->p_node, ptr, AVL_PTR_SIZE);
  374. mpc_select(tio, yield, ret->dir_pc, imbalance, ret->dir_pc, gt);
  375. // Save child pointer
  376. mpc_select(tio, yield, ret->c_node, imbalance, ret->c_node, prev_node, AVL_PTR_SIZE);
  377. mpc_select(tio, yield, ret->dir_cn, imbalance, ret->dir_cn, prev_dir);
  378. // Store new_bal_l and new_bal_r for this node
  379. // but this can be handled in the rotation component in one shot,
  380. // since insertion rotations always resolve with p,c having 0,0 balance
  381. setLeftBal(cnode.pointers, new_bal_l);
  382. setRightBal(cnode.pointers, new_bal_r);
  383. A[ptr].NODE_POINTERS = cnode.pointers;
  384. // s0 = shares of 0
  385. RegBS s0;
  386. // Update F_gp flag: If there was an imbalance then we set this to store
  387. // the grandparent node (node in the level above) into the ret_struct
  388. mpc_select(tio, yield, F_gp, imbalance, s0, imbalance);
  389. return {new_bal_upd, F_gp, ptr, gt};
  390. }
  391. // Insert(root, ptr, key, TTL, isDummy) -> (new_ptr, wptr, wnode, f_p)
  392. void AVL::insert(MPCTIO &tio, yield_t &yield, const Node &node) {
  393. bool player0 = tio.player()==0;
  394. auto A = oram->flat(tio, yield);
  395. // If there are no items in tree. Make this new item the root.
  396. if(num_items==0) {
  397. Node zero;
  398. A[0] = zero;
  399. A[1] = node;
  400. (root).set(1*tio.player());
  401. num_items++;
  402. return;
  403. } else {
  404. // Insert node into next free slot in the ORAM
  405. int new_id;
  406. RegXS insert_address;
  407. num_items++;
  408. int TTL = AVL_TTL(num_items);
  409. bool insertAtEmptyLocation = (numEmptyLocations() > 0);
  410. if(insertAtEmptyLocation) {
  411. insert_address = empty_locations.back();
  412. empty_locations.pop_back();
  413. A[insert_address] = node;
  414. } else {
  415. new_id = num_items;
  416. A[new_id] = node;
  417. insert_address.set(new_id * tio.player());
  418. }
  419. RegBS isDummy;
  420. avl_insert_return ret;
  421. RegAS insert_key = node.key;
  422. // Recursive insert function
  423. auto [bal_upd, F_gp, prev_node, prev_dir] = insert(tio, yield, root, insert_key, A, TTL, isDummy, &ret);
  424. /*
  425. // Debug code
  426. bool rec_bal_upd, rec_F_gp, ret_dir_pc, ret_dir_cn;
  427. rec_bal_upd = reconstruct_RegBS(tio, yield, bal_upd);
  428. rec_F_gp = reconstruct_RegBS(tio, yield, F_gp);
  429. ret_dir_pc = reconstruct_RegBS(tio, yield, ret.dir_pc);
  430. ret_dir_cn = reconstruct_RegBS(tio, yield, ret.dir_cn);
  431. printf("(Top level) Insert returns: rec_bal_upd = %d, rec_F_gp = %d\n",
  432. rec_bal_upd, rec_F_gp);
  433. printf("(Top level) Insert returns: ret.dir_pc = %d, rt.dir_cn = %d\n",
  434. ret_dir_pc, ret_dir_cn);
  435. */
  436. // Perform actual insertion
  437. RegXS ins_pointers = A[ret.i_node].NODE_POINTERS;
  438. RegXS left_ptr = getAVLLeftPtr(ins_pointers);
  439. RegXS right_ptr = getAVLRightPtr(ins_pointers);
  440. mpc_select(tio, yield, right_ptr, ret.dir_i, right_ptr, insert_address, AVL_PTR_SIZE);
  441. // ret.dir_i -> !(ret.dir_i)
  442. if(player0) {
  443. ret.dir_i^=1;
  444. }
  445. mpc_select(tio, yield, left_ptr, ret.dir_i, left_ptr, insert_address, AVL_PTR_SIZE);
  446. // We never use ret.dir_i again, so don't bother reverting the negation above.
  447. setAVLLeftPtr(ins_pointers, left_ptr);
  448. setAVLRightPtr(ins_pointers, right_ptr);
  449. A[ret.i_node].NODE_POINTERS = ins_pointers;
  450. // Perform balance procedure
  451. RegXS gp_pointers = A[ret.gp_node].NODE_POINTERS;
  452. RegXS parent_pointers = A[ret.p_node].NODE_POINTERS;
  453. RegXS child_pointers = A[ret.c_node].NODE_POINTERS;
  454. // n_node (child's next node)
  455. RegXS child_left = getAVLLeftPtr(child_pointers);
  456. RegXS child_right = getAVLRightPtr(child_pointers);
  457. RegXS n_node;
  458. mpc_select(tio, yield, n_node, ret.dir_cn, n_node, child_right, AVL_PTR_SIZE);
  459. // dir_cn -> !(dir_cn); to handle left case
  460. if(player0) {
  461. ret.dir_cn^=1;
  462. }
  463. mpc_select(tio, yield, n_node, ret.dir_cn, n_node, child_left, AVL_PTR_SIZE);
  464. // Undo dir_cn negation
  465. if(player0) {
  466. ret.dir_cn^=1;
  467. }
  468. RegXS n_pointers = A[n_node].NODE_POINTERS;
  469. // F_dr = (dir_pc != dir_cn) : i.e., double rotation case if
  470. // (parent->child) and (child->new_node) are not in the same direction
  471. RegBS F_dr = (ret.dir_pc) ^ (ret.dir_cn);
  472. /* Flags: F_cn_rot = child->node rotate
  473. F_ur = update root.
  474. In case of an imbalance we have to always rotate p->c link. (L or R case)
  475. In case of an imbalance where p->c and c->n are in different directions, we have
  476. to perform a double rotation (LR or RL case). In such cases, first rotate
  477. c->n link, and then p->c link
  478. (Note: in the second rotation c is actually n, since the the first rotation
  479. swaps their positions)
  480. */
  481. RegBS F_cn_rot, F_ur;
  482. mpc_and(tio, yield, F_ur, F_gp, ret.imbalance);
  483. mpc_and(tio, yield, F_cn_rot, ret.imbalance, F_dr);
  484. RegBS s0;
  485. // Get the n children information for 2nd rotate fix before rotations happen.
  486. RegBS n_bal_l, n_bal_r;
  487. RegXS n_l = getAVLLeftPtr(n_pointers);
  488. RegXS n_r = getAVLRightPtr(n_pointers);
  489. n_bal_l = getLeftBal(n_pointers);
  490. n_bal_r = getRightBal(n_pointers);
  491. // First rotation: c->n link
  492. rotate(tio, yield, parent_pointers, ret.c_node, child_pointers, n_node,
  493. n_pointers, ret.dir_pc, ret.dir_cn, F_cn_rot, s0);
  494. // If F_cn_rot, i.e. we did first rotation. Then c and n need to swap before the second rotate.
  495. RegXS new_child_pointers, new_child;
  496. mpc_select(tio, yield, new_child_pointers, F_cn_rot, child_pointers, n_pointers);
  497. mpc_select(tio, yield, new_child, F_cn_rot, ret.c_node, n_node, AVL_PTR_SIZE);
  498. // Second rotation: p->c link
  499. rotate(tio, yield, gp_pointers, ret.p_node, parent_pointers, new_child,
  500. new_child_pointers, ret.dir_gpp, ret.dir_pc, ret.imbalance, F_gp);
  501. // Set parent and child balances to 0 if there was an imbalance.
  502. // parent balances are already set to 0 from updateBalanceIns
  503. RegBS temp_bal, p_bal_l, p_bal_r, p_bal_ndpc;
  504. RegBS c_bal_l, c_bal_r, c_bal_dpc, n_bal_dpc, n_bal_ndpc;
  505. p_bal_l = getLeftBal(parent_pointers);
  506. p_bal_r = getRightBal(parent_pointers);
  507. mpc_select(tio, yield, child_pointers, F_cn_rot, new_child_pointers, child_pointers);
  508. mpc_select(tio, yield, n_pointers, F_cn_rot, n_pointers, new_child_pointers);
  509. c_bal_l = getLeftBal(child_pointers);
  510. c_bal_r = getRightBal(child_pointers);
  511. mpc_select(tio, yield, c_bal_l, ret.imbalance, c_bal_l, s0);
  512. mpc_select(tio, yield, c_bal_r, ret.imbalance, c_bal_r, s0);
  513. /* In the double rotation case: balance of c and p have a tweak
  514. p_bal_ndpc <- !(n_bal_ndpc)
  515. c_bal_dpc <- !(n_bal_dpc) */
  516. CDPF cdpf = tio.cdpf(yield);
  517. size_t &aes_ops = tio.aes_ops();
  518. RegBS n_l0 = cdpf.is_zero(tio, yield, n_l, aes_ops);
  519. RegBS n_r0 = cdpf.is_zero(tio, yield, n_r, aes_ops);
  520. RegBS p_c_update, n_has_children;
  521. // n_has_children = !(n_l0 & n_r0)
  522. mpc_and(tio, yield, n_has_children, n_l0, n_r0);
  523. if(player0) {
  524. n_has_children^=1;
  525. }
  526. /*
  527. bool rec_n_l0, rec_n_r0, rec_n_hc;
  528. rec_n_l0 = reconstruct_RegBS(tio, yield, n_l0);
  529. rec_n_r0 = reconstruct_RegBS(tio, yield, n_r0);
  530. rec_n_hc = reconstruct_RegBS(tio, yield, n_has_children);
  531. printf("n_l0 = %d, n_r0 = %d, n_has_children = %d\n", rec_n_l0, rec_n_r0, rec_n_hc);
  532. */
  533. mpc_and(tio, yield, p_c_update, F_cn_rot, n_has_children);
  534. mpc_select(tio, yield, n_bal_ndpc, ret.dir_pc, n_bal_r, n_bal_l);
  535. mpc_select(tio, yield, n_bal_dpc, ret.dir_pc, n_bal_l, n_bal_r);
  536. mpc_select(tio, yield, p_bal_ndpc, ret.dir_pc, p_bal_r, p_bal_l);
  537. // !n_bal_ndpc, !n_bal_dpc
  538. if(player0) {
  539. n_bal_ndpc^=1;
  540. n_bal_dpc^=1;
  541. }
  542. mpc_select(tio, yield, p_bal_ndpc, p_c_update, p_bal_ndpc, n_bal_ndpc);
  543. mpc_select(tio, yield, c_bal_dpc, p_c_update, c_bal_dpc, n_bal_dpc);
  544. mpc_select(tio, yield, p_bal_r, ret.dir_pc, p_bal_ndpc, p_bal_r);
  545. mpc_select(tio, yield, p_bal_l, ret.dir_pc, p_bal_l, p_bal_ndpc);
  546. mpc_select(tio, yield, c_bal_r, ret.dir_pc, c_bal_r, c_bal_dpc);
  547. mpc_select(tio, yield, c_bal_l, ret.dir_pc, c_bal_dpc, c_bal_l);
  548. setLeftBal(parent_pointers, p_bal_l);
  549. setRightBal(parent_pointers, p_bal_r);
  550. setLeftBal(child_pointers, c_bal_l);
  551. setRightBal(child_pointers, c_bal_r);
  552. // Write back update pointers and balances into gp, p, c, and n
  553. A[ret.c_node].NODE_POINTERS = child_pointers;
  554. A[ret.p_node].NODE_POINTERS = parent_pointers;
  555. A[ret.gp_node].NODE_POINTERS = gp_pointers;
  556. A[n_node].NODE_POINTERS = n_pointers;
  557. // Handle root pointer switch (if F_gp is true in the return from insert())
  558. // If F_gp and we did a double rotation: root <-- new node
  559. // If F_gp and we did a single rotation: root <-- child node
  560. mpc_select(tio, yield, root, F_ur, root, ret.c_node, AVL_PTR_SIZE);
  561. mpc_and(tio, yield, F_ur, F_gp, F_dr);
  562. mpc_select(tio, yield, root, F_ur, root, n_node, AVL_PTR_SIZE);
  563. }
  564. }
  565. bool AVL::lookup(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS key, Duoram<Node>::Flat &A,
  566. int TTL, RegBS isDummy, Node *ret_node) {
  567. if(TTL==0) {
  568. // Reconstruct and return isDummy
  569. // If we found the key, then isDummy will be true
  570. bool found = reconstruct_RegBS(tio, yield, isDummy);
  571. return found;
  572. }
  573. RegBS isNotDummy = isDummy ^ (tio.player());
  574. Node cnode = A[ptr];
  575. // Compare key
  576. CDPF cdpf = tio.cdpf(yield);
  577. auto [lt, eq, gt] = cdpf.compare(tio, yield, key - cnode.key, tio.aes_ops());
  578. // Depending on [lteq, gt] select the next ptr/index as
  579. // upper 32 bits of cnode.pointers if lteq
  580. // lower 32 bits of cnode.pointers if gt
  581. RegXS left = getAVLLeftPtr(cnode.pointers);
  582. RegXS right = getAVLRightPtr(cnode.pointers);
  583. RegXS next_ptr;
  584. mpc_select(tio, yield, next_ptr, gt, left, right, 32);
  585. RegBS F_found;
  586. // If we haven't found the key yet, and the lookup matches the current node key,
  587. // then we found the node to return
  588. mpc_and(tio, yield, F_found, isNotDummy, eq);
  589. mpc_select(tio, yield, ret_node->key, eq, ret_node->key, cnode.key);
  590. mpc_select(tio, yield, ret_node->value, eq, ret_node->value, cnode.value);
  591. isDummy^=F_found;
  592. bool found = lookup(tio, yield, next_ptr, key, A, TTL-1, isDummy, ret_node);
  593. return found;
  594. }
  595. bool AVL::lookup(MPCTIO &tio, yield_t &yield, RegAS key, Node *ret_node) {
  596. auto A = oram->flat(tio, yield);
  597. RegBS isDummy;
  598. bool found = lookup(tio, yield, root, key, A, num_items, isDummy, ret_node);
  599. return found;
  600. }
  601. std::tuple<bool, RegBS> AVL::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
  602. Duoram<Node>::Flat &A, RegBS af, RegBS fs, int TTL,
  603. avl_del_return &ret_struct) {
  604. bool player0 = tio.player()==0;
  605. if(TTL==0) {
  606. //Reconstruct and return af
  607. bool success = reconstruct_RegBS(tio, yield, af);
  608. RegBS zero;
  609. //printf("Reconstructed flag = %d\n", success);
  610. if(player0)
  611. ret_struct.F_r^=1;
  612. return {success, zero};
  613. } else {
  614. Node node = A[ptr];
  615. // Compare key
  616. CDPF cdpf = tio.cdpf(yield);
  617. auto [lt, eq, gt] = cdpf.compare(tio, yield, del_key - node.key, tio.aes_ops());
  618. // c is the direction bit for next_ptr
  619. // (c=0: go left or c=1: go right)
  620. RegBS c = gt;
  621. // lf = local found. We found the key to delete in this level.
  622. RegBS lf = eq;
  623. // Select the next ptr
  624. RegXS left = getAVLLeftPtr(node.pointers);
  625. RegXS right = getAVLRightPtr(node.pointers);
  626. size_t &aes_ops = tio.aes_ops();
  627. // Check if left and right children are 0, and compute F_0, F_1, F_2
  628. RegBS l0 = cdpf.is_zero(tio, yield, left, aes_ops);
  629. RegBS r0 = cdpf.is_zero(tio, yield, right, aes_ops);
  630. RegBS F_0, F_1, F_2;
  631. // F_0 = l0 & r0
  632. mpc_and(tio, yield, F_0, l0, r0);
  633. // F_1 = l0 \xor r0
  634. F_1 = l0 ^ r0;
  635. // F_2 = !(F_0 + F_1) (Only 1 of F_0, F_1, and F_2 can be true)
  636. F_2 = F_0 ^ F_1;
  637. if(player0)
  638. F_2^=1;
  639. // We set next ptr based on c, but we need to handle three
  640. // edge cases where we do not pick next_ptr by just the comparison result
  641. RegXS next_ptr, cs_ptr;
  642. RegBS c_prime;
  643. // Case 1: found the node here (lf), and node has only one child.
  644. // Then we iterate down the only child.
  645. RegBS F_c1, F_c2, F_c3, F_c4;
  646. // Case 1: lf & F_1
  647. mpc_and(tio, yield, F_c1, lf, F_1);
  648. // Set c_prime for Case 1
  649. mpc_select(tio, yield, c_prime, F_c1, c, l0);
  650. // s1: shares of 1 bit, s0: shares of 0 bit
  651. RegBS s1, s0;
  652. s1.set(tio.player()==1);
  653. // Case 2: found the node here (lf) and node has both children (F_2)
  654. // In find successor case, so we find inorder successor for node to be deleted
  655. // (inorder successor = go right and then find leftmost child.)
  656. mpc_and(tio, yield, F_c2, lf, F_2);
  657. mpc_select(tio, yield, c_prime, F_c2, c_prime, s1);
  658. /*
  659. // Reconstruct and Debug Block 2
  660. bool F_c2_rec, s1_rec;
  661. F_c2_rec = reconstruct_RegBS(tio, yield, F_c2);
  662. s1_rec = reconstruct_RegBS(tio, yield, s1);
  663. c_prime_rec = reconstruct_RegBS(tio, yield, c_prime);
  664. printf("c_prime = %d, F_c2 = %d, s1 = %d\n", c_prime_rec, F_c2_rec, s1_rec);
  665. */
  666. // Case 3: finding successor (fs) and node has both children (F_2)
  667. // Go left.
  668. mpc_and(tio, yield, F_c3, fs, F_2);
  669. mpc_select(tio, yield, c_prime, F_c3, c_prime, s0);
  670. // Case 4: finding successor (fs) and node has no more left children (l0)
  671. // This is the successor node then.
  672. // Go right (since no more left)
  673. mpc_and(tio, yield, F_c4, fs, l0);
  674. mpc_select(tio, yield, c_prime, F_c4, c_prime, l0);
  675. // Set next_ptr
  676. mpc_select(tio, yield, next_ptr, c_prime, left, right, AVL_PTR_SIZE);
  677. // cs_ptr: child's sibling pointer
  678. mpc_select(tio, yield, cs_ptr, c_prime, right, left, AVL_PTR_SIZE);
  679. RegBS af_prime, fs_prime;
  680. mpc_or(tio, yield, af_prime, af, lf);
  681. // If in Case 2, set fs. We are now finding successor
  682. mpc_or(tio, yield, fs_prime, fs, F_c2);
  683. // If in Case 4. Successor found here already. Toggle fs off
  684. fs_prime=fs_prime^F_c4;
  685. TTL-=1;
  686. auto [key_found, bal_upd] = del(tio, yield, next_ptr, del_key, A, af_prime, fs_prime, TTL, ret_struct);
  687. // If we didn't find the key, we can end here.
  688. if(!key_found) {
  689. return {0, s0};
  690. }
  691. /* F_rs: Flag for updating the correct child pointer of this node
  692. This happens if F_r is set in ret_struct. F_r indicates if we need
  693. to update a child pointer at this level by skipping the current
  694. child in the direction of traversal. We do this in two cases:
  695. i) F_d & (!F_2) : If we delete here, and this node does not have
  696. 2 children (;i.e., we are not in the finding successor case)
  697. ii) F_ns: Found the successor (no more left children while
  698. traversing to find successor)
  699. In cases i and ii we skip the next node, and make the current node
  700. point to the node after the next node.
  701. iii) We did rotation(s) at the lower level, changing the child in
  702. that position. So we update it to the correct node in that
  703. position now.
  704. Whether skip happens or just update happens is handled by how
  705. ret_struct.ret_ptr is set.
  706. */
  707. RegBS F_rr; // Flag to resolve F_r by updating correct child ptr
  708. mpc_and(tio, yield, F_rr, c_prime, ret_struct.F_r);
  709. mpc_select(tio, yield, right, F_rr, right, ret_struct.ret_ptr);
  710. if(player0)
  711. c_prime^=1;
  712. mpc_and(tio, yield, F_rr, c_prime, ret_struct.F_r);
  713. mpc_select(tio, yield, left, F_rr, left, ret_struct.ret_ptr);
  714. if(player0)
  715. c_prime^=1;
  716. setAVLLeftPtr(node.pointers, left);
  717. setAVLRightPtr(node.pointers, right);
  718. // Delay storing pointers back until balance updates are done as well.
  719. // Since we resolved the F_r flag returned, we set it back to 0.
  720. ret_struct.F_r = s0;
  721. RegBS p_bal_l, p_bal_r;
  722. p_bal_l = getLeftBal(node.pointers);
  723. p_bal_r = getRightBal(node.pointers);
  724. auto [new_p_bal_l, new_p_bal_r, new_bal_upd, imb] =
  725. updateBalanceDel(tio, yield, p_bal_l, p_bal_r, bal_upd, c_prime);
  726. /*
  727. // Reconstruct and Debug Block
  728. bool rec_new_bal_upd, rec_imb, rec_bal_upd;
  729. size_t rec_ckey;
  730. rec_new_bal_upd = reconstruct_RegBS(tio, yield, new_bal_upd);
  731. rec_imb = reconstruct_RegBS(tio, yield, imb);
  732. rec_bal_upd = reconstruct_RegBS(tio, yield, bal_upd);
  733. rec_ckey = reconstruct_RegAS(tio, yield, node.key);
  734. bool rec_F_c1, rec_F_c2, rec_F_c3, rec_F_c4;
  735. rec_F_c1 = reconstruct_RegBS(tio, yield, F_c1);
  736. rec_F_c2 = reconstruct_RegBS(tio, yield, F_c2);
  737. rec_F_c3 = reconstruct_RegBS(tio, yield, F_c3);
  738. rec_F_c4 = reconstruct_RegBS(tio, yield, F_c4);
  739. printf("Current Key = %lu\n", rec_ckey);
  740. size_t rec_p_left_0, rec_p_right_0;
  741. rec_p_left_0 = reconstruct_RegXS(tio, yield, getAVLLeftPtr(node.pointers));
  742. rec_p_right_0 = reconstruct_RegXS(tio, yield, getAVLRightPtr(node.pointers));
  743. printf("parent_ptrs (after read): left = %lu, right = %lu\n", rec_p_left_0, rec_p_right_0);
  744. printf("F_c1 = %d, F_c2 = %d, F_c3 = %d, F_c4 = %d\n", rec_F_c1, rec_F_c2, rec_F_c3, rec_F_c4);
  745. printf("bal_upd = %d, new_bal_upd = %d, imb= %d\n", rec_bal_upd, rec_new_bal_upd, rec_imb);
  746. */
  747. // F_ri: subflag for F_r. F_ri = returned flag set to 1 from imbalance fix.
  748. RegBS F_ri;
  749. // Perform rotations if imbalance (else dummy rotations)
  750. /*
  751. For capturing both the symmetric L and R cases of rotations, we'll capture directions with
  752. dpc = dir_pc = direction from parent to child, and
  753. ndpc = not(dir_pc)
  754. When we travelled down the stack, we went from p->c. But in deletions to handle any imbalance
  755. we look at c's sibling cs (child's sibling). And the rotation is between p and cs if there
  756. was an imbalance at p, and perhaps even cs and it's child (the child in dir_pc, as that's the
  757. only case that results in a double rotation when deleting).
  758. In case of an imbalance we have to always rotate p->cs link. (L or R case)
  759. If cs.bal_(dir_pc), then we have a double rotation (LR or RL) case.
  760. In such cases, first rotate cs->gcs link, and then p->cs link. gcs = grandchild on cs path
  761. Layout: In the R (or LR) case:
  762. p
  763. / \
  764. cs c
  765. / \
  766. a gcs
  767. / \
  768. x y
  769. - One of x or y must exist for it to be an LR case,
  770. since then cs.bal_(dir_pc) = cs.bal_r = 1
  771. Layout: In the L (or RL) case:
  772. p
  773. / \
  774. c cs
  775. / \
  776. gcs a
  777. / \
  778. x y
  779. - One of x or y must exist for it to be an RL case,
  780. since then cs.bal_(dir_pc) = cs.bal_l = 1
  781. (Note: if double rotation case, in the second rotation cs is actually gcs,
  782. since the the first rotation swaps their positions)
  783. */
  784. Node cs_node = A[cs_ptr];
  785. //dirpc = dir_pc = dpc = c_prime
  786. RegBS cs_bal_l, cs_bal_r, cs_bal_dpc, cs_bal_ndpc, F_dr, not_c_prime;
  787. RegXS gcs_ptr, cs_left, cs_right, cs_dpc, cs_ndpc, null;
  788. // child's sibling node's balances in dir_pc (dpc), and not_dir_pc (ndpc)
  789. cs_bal_l = getLeftBal(cs_node.pointers);
  790. cs_bal_r = getRightBal(cs_node.pointers);
  791. cs_left = getAVLLeftPtr(cs_node.pointers);
  792. cs_right = getAVLRightPtr(cs_node.pointers);
  793. mpc_select(tio, yield, cs_bal_dpc, c_prime, cs_bal_l, cs_bal_r);
  794. mpc_select(tio, yield, cs_bal_ndpc, c_prime, cs_bal_r, cs_bal_l);
  795. mpc_select(tio, yield, cs_dpc, c_prime, cs_left, cs_right);
  796. mpc_select(tio, yield, cs_ndpc, c_prime, cs_right, cs_left);
  797. // We need to double rotate (LR or RL case) if cs_bal_dpc is 1
  798. mpc_and(tio, yield, F_dr, imb, cs_bal_dpc);
  799. mpc_select(tio, yield, gcs_ptr, cs_bal_dpc, cs_ndpc, cs_dpc, AVL_PTR_SIZE);
  800. Node gcs_node = A[gcs_ptr];
  801. not_c_prime = c_prime;
  802. if(player0) {
  803. not_c_prime^=1;
  804. }
  805. // First rotation: cs->gcs link
  806. rotate(tio, yield, node.pointers, cs_ptr, cs_node.pointers, gcs_ptr,
  807. gcs_node.pointers, not_c_prime, c_prime, F_dr, s0);
  808. // If F_dr, we did first rotation. Then cs and gcs need to swap before the second rotate.
  809. RegXS new_cs_pointers, new_cs, new_ptr;
  810. mpc_select(tio, yield, new_cs_pointers, F_dr, cs_node.pointers, gcs_node.pointers);
  811. mpc_select(tio, yield, new_cs, F_dr, cs_ptr, gcs_ptr, AVL_PTR_SIZE);
  812. // Second rotation: p->cs link
  813. // Since we don't have access to gp node here we just send a null and s0
  814. // for gp_pointers and dir_gpp. Instead this pointer fix is handled by F_r
  815. // and ret_struct.ret_ptr.
  816. rotate(tio, yield, null, ptr, node.pointers, new_cs,
  817. new_cs_pointers, s0, not_c_prime, imb, s1);
  818. /*
  819. size_t rec_p_left_1, rec_p_right_1;
  820. bool rec_flag_imb, rec_flag_dr;
  821. rec_flag_imb = reconstruct_RegBS(tio, yield, imb);
  822. rec_flag_dr = reconstruct_RegBS(tio, yield, F_dr);
  823. rec_p_left_1 = reconstruct_RegXS(tio, yield, getAVLLeftPtr(node.pointers));
  824. rec_p_right_1 = reconstruct_RegXS(tio, yield, getAVLRightPtr(node.pointers));
  825. printf("flag_imb = %d, flag_dr = %d\n", rec_flag_imb, rec_flag_dr);
  826. printf("parent_ptrs (after rotations): left = %lu, right = %lu\n", rec_p_left_1, rec_p_right_1);
  827. */
  828. // If imb (we do some rotation), then update F_r, and ret_ptr, to
  829. // fix the gp->p link (The F_r clauses later, and this are mutually
  830. // exclusive events. They will never trigger together.)
  831. mpc_select(tio, yield, new_ptr, F_dr, cs_ptr, gcs_ptr);
  832. mpc_select(tio, yield, F_ri, imb, s0, s1);
  833. mpc_select(tio, yield, ret_struct.ret_ptr, imb, ret_struct.ret_ptr, new_ptr);
  834. // Write back new_cs_pointers correctly to (cs_node/gcs_node).pointers
  835. // and then balance the nodes
  836. mpc_select(tio, yield, cs_node.pointers, F_dr, new_cs_pointers, cs_node.pointers);
  837. mpc_select(tio, yield, gcs_node.pointers, F_dr, gcs_node.pointers, new_cs_pointers);
  838. /*
  839. Update balances based on imbalance and type of rotations that happen.
  840. In the case of an imbalance, updateBalance() sets bal_l and bal_r of p to 0.
  841. */
  842. RegBS IC1, IC2, IC3; // Imbalance Case 1, 2 or 3
  843. // IC1 = Single rotation (L/R). L/R = dpc
  844. mpc_and(tio, yield, IC1, imb, cs_bal_ndpc);
  845. // IC3 = Double rotation (LR/RL). 1st rotate direction = ndpc, 2nd direction = dpc
  846. mpc_and(tio, yield, IC3, imb, cs_bal_dpc);
  847. // IC2 = Single rotation (L/R).
  848. IC2 = IC1 ^ IC3;
  849. if(player0) {
  850. IC2^=1;
  851. }
  852. mpc_and(tio, yield, IC2, imb, IC2);
  853. /*
  854. bool rec_IC1, rec_IC2, rec_IC3;
  855. rec_IC1 = reconstruct_RegBS(tio, yield, IC1);
  856. rec_IC2 = reconstruct_RegBS(tio, yield, IC2);
  857. rec_IC3 = reconstruct_RegBS(tio, yield, IC3);
  858. printf("rec_IC1 = %d, rec_IC2 = %d, rec_IC3 = %d\n", rec_IC1, rec_IC2, rec_IC3);
  859. */
  860. // IC1, IC2, IC3: CS.bal = 0 0
  861. mpc_select(tio, yield, cs_bal_dpc, imb, cs_bal_dpc, s0);
  862. mpc_select(tio, yield, cs_bal_ndpc, imb, cs_bal_ndpc, s0);
  863. mpc_select(tio, yield, cs_bal_r, c_prime, cs_bal_ndpc, cs_bal_dpc);
  864. mpc_select(tio, yield, cs_bal_l, c_prime, cs_bal_dpc, cs_bal_ndpc);
  865. // IC2: p.bal_ndpc = 1, cs.bal_dpc = 1
  866. // (IC2 & not_c_prime)
  867. cs_bal_dpc^=IC2;
  868. RegBS p_bal_dpc, p_bal_ndpc;
  869. mpc_select(tio, yield, p_bal_ndpc, c_prime, new_p_bal_r, new_p_bal_l);
  870. p_bal_ndpc^=IC2;
  871. RegBS IC2_ndpc_l, IC2_ndpc_r, IC2_dpc_l, IC2_dpc_r;
  872. mpc_and(tio, yield, IC2_ndpc_l, IC2, c_prime);
  873. mpc_and(tio, yield, IC2_ndpc_r, IC2, not_c_prime);
  874. mpc_and(tio, yield, IC2_dpc_l, IC2, not_c_prime);
  875. mpc_and(tio, yield, IC2_dpc_r, IC2, c_prime);
  876. mpc_select(tio, yield, new_p_bal_l, IC2_ndpc_l, new_p_bal_l, p_bal_ndpc);
  877. mpc_select(tio, yield, new_p_bal_r, IC2_ndpc_r, new_p_bal_r, p_bal_ndpc);
  878. mpc_select(tio, yield, cs_bal_l, IC2_dpc_l, cs_bal_l, cs_bal_dpc);
  879. mpc_select(tio, yield, cs_bal_r, IC2_dpc_r, cs_bal_r, cs_bal_dpc);
  880. // In the IC2 case bal_upd = 0 (The rotation doesn't end up
  881. // decreasing height of this subtree.
  882. mpc_select(tio, yield, bal_upd, IC2, bal_upd, s0);
  883. // IC3:
  884. // To set balance in this case we need to know if gcs.dpc child exists
  885. // and similarly if gcs.ndpc child exitst.
  886. // if(gcs.ndpc child exists): cs.bal_ndpc = 1
  887. // if(gcs.dpc child exists): p.bal_dpc = 1
  888. RegBS gcs_dpc_exists, gcs_ndpc_exists;
  889. RegXS gcs_l = getAVLLeftPtr(gcs_node.pointers);
  890. RegXS gcs_r = getAVLRightPtr(gcs_node.pointers);
  891. RegBS gcs_bal_l = getLeftBal(gcs_node.pointers);
  892. RegBS gcs_bal_r = getRightBal(gcs_node.pointers);
  893. RegXS gcs_dpc, gcs_ndpc;
  894. mpc_select(tio, yield, gcs_dpc, c_prime, gcs_l, gcs_r);
  895. mpc_select(tio, yield, gcs_ndpc, not_c_prime, gcs_l, gcs_r);
  896. gcs_dpc_exists = cdpf.is_zero(tio, yield, gcs_dpc, aes_ops);
  897. gcs_ndpc_exists = cdpf.is_zero(tio, yield, gcs_ndpc, aes_ops);
  898. cs_bal_ndpc^=IC3;
  899. RegBS IC3_ndpc_l, IC3_ndpc_r, IC3_dpc_l, IC3_dpc_r;
  900. mpc_and(tio, yield, IC3_ndpc_l, IC3, c_prime);
  901. mpc_and(tio, yield, IC3_ndpc_r, IC3, not_c_prime);
  902. mpc_and(tio, yield, IC3_dpc_l, IC3, not_c_prime);
  903. mpc_and(tio, yield, IC3_dpc_r, IC3, c_prime);
  904. RegBS f0, f1, f2, f3;
  905. mpc_and(tio, yield, f0, IC3_dpc_l, gcs_dpc_exists);
  906. mpc_and(tio, yield, f1, IC3_dpc_r, gcs_dpc_exists);
  907. mpc_and(tio, yield, f2, IC3_ndpc_l, gcs_ndpc_exists);
  908. mpc_and(tio, yield, f3, IC3_ndpc_r, gcs_ndpc_exists);
  909. mpc_select(tio, yield, new_p_bal_l, f0, new_p_bal_l, IC3);
  910. mpc_select(tio, yield, new_p_bal_r, f1, new_p_bal_r, IC3);
  911. mpc_select(tio, yield, cs_bal_l, f2, cs_bal_l, IC3);
  912. mpc_select(tio, yield, cs_bal_r, f3, cs_bal_r, IC3);
  913. // In IC3 gcs.bal = 0 0
  914. mpc_select(tio, yield, gcs_bal_l, IC3, gcs_bal_l, s0);
  915. mpc_select(tio, yield, gcs_bal_r, IC3, gcs_bal_r, s0);
  916. // Write back <cs_bal_dpc, cs_bal_ndpc> and <gcs_bal_l, gcs_bal_r>
  917. setLeftBal(gcs_node.pointers, gcs_bal_l);
  918. setRightBal(gcs_node.pointers, gcs_bal_r);
  919. setLeftBal(cs_node.pointers, cs_bal_l);
  920. setRightBal(cs_node.pointers, cs_bal_r);
  921. A[cs_ptr].NODE_POINTERS = cs_node.pointers;
  922. A[gcs_ptr].NODE_POINTERS = gcs_node.pointers;
  923. // Write back updated pointers correctly accounting for rotations
  924. setLeftBal(node.pointers, new_p_bal_l);
  925. setRightBal(node.pointers, new_p_bal_r);
  926. A[ptr].NODE_POINTERS = node.pointers;
  927. // Update the return structure
  928. // F_dh = Delete Here flag,
  929. // F_sf = successor found (no more left children while trying to find successor)
  930. // F_rs = subflag for F_r. F_rs = flag for F_r set to 1 from handling a skip fix
  931. // (deleting a node with single child, or found successor cases)
  932. RegBS F_dh, F_sf, F_rs;
  933. mpc_or(tio, yield, ret_struct.F_ss, ret_struct.F_ss, F_c2);
  934. if(player0)
  935. af^=1;
  936. mpc_and(tio, yield, F_dh, lf, af);
  937. mpc_select(tio, yield, ret_struct.N_d, F_dh, ret_struct.N_d, ptr);
  938. // F_sf = Successor found = F_c4 = Finding successor & no more left child
  939. F_sf = F_c4;
  940. if(player0)
  941. F_2^=1;
  942. // If we have to i) delete here, and it doesn't have two children
  943. // we have to update child pointer in parent with the returned pointer
  944. mpc_and(tio, yield, F_rs, F_dh, F_2);
  945. // ii) if we found successor here
  946. mpc_or(tio, yield, F_rs, F_rs, F_sf);
  947. mpc_select(tio, yield, ret_struct.N_s, F_sf, ret_struct.N_s, ptr);
  948. // F_rs and F_ri will never trigger together. So the line below
  949. // set ret_ptr to the correct pointer to handle either case
  950. // If neither F_rs nor F_ri, we set the ret_ptr to current ptr.
  951. RegBS F_nr;
  952. mpc_or(tio, yield, F_nr, F_rs, F_ri);
  953. // F_nr = F_rs || F_ri
  954. ret_struct.F_r = F_nr;
  955. /*
  956. bool rec_ret_F_r, rec_F_rs, rec_F_ri;
  957. rec_ret_F_r = reconstruct_RegBS(tio, yield, ret_struct.F_r);
  958. rec_F_rs = reconstruct_RegBS(tio, yield, F_rs);
  959. rec_F_ri = reconstruct_RegBS(tio, yield, F_ri);
  960. printf("rec_ret_F_r = %d, rec_F_rs = %d, rec_F_ri = %d\n", rec_ret_F_r, rec_F_rs, rec_F_ri);
  961. */
  962. if(player0) {
  963. F_nr^=1;
  964. }
  965. // F_nr = !(F_rs || F_ri)
  966. mpc_select(tio, yield, ret_struct.ret_ptr, F_nr, ret_struct.ret_ptr, ptr);
  967. // If F_rs, we skipped a node, so update bal_upd to 1
  968. mpc_select(tio, yield, bal_upd, F_rs, bal_upd, s1);
  969. /*
  970. rec_F_rs = reconstruct_RegBS(tio, yield, F_rs);
  971. bool rec_bal_upd_set = reconstruct_RegBS(tio, yield, bal_upd);
  972. printf("after bal_upd select from rec_F_rs = %d, rec_bal_upd = %d\n",
  973. rec_F_rs, rec_bal_upd_set);
  974. */
  975. // Swap deletion node with successor node done outside of recursive traversal.
  976. return {key_found, bal_upd};
  977. }
  978. }
  979. bool AVL::del(MPCTIO &tio, yield_t &yield, RegAS del_key) {
  980. if(num_items==0)
  981. return 0;
  982. auto A = oram->flat(tio, yield);
  983. if(num_items==1) {
  984. //Delete root
  985. Node zero;
  986. empty_locations.emplace_back(root);
  987. A[root] = zero;
  988. num_items--;
  989. return 1;
  990. } else {
  991. int TTL = AVL_TTL(num_items);
  992. // Flags for already found (af) item to delete and find successor (fs)
  993. // if this deletion requires a successor swap
  994. RegBS af, fs;
  995. avl_del_return ret_struct;
  996. auto [success, bal_upd] = del(tio, yield, root, del_key, A, af, fs, TTL, ret_struct);
  997. printf ("Success = %d\n", success);
  998. if(!success){
  999. return 0;
  1000. }
  1001. else{
  1002. num_items--;
  1003. printf("In delete's swap portion\n");
  1004. Node rec_del_node = A.reconstruct(A[ret_struct.N_d]);
  1005. Node rec_suc_node = A.reconstruct(A[ret_struct.N_s]);
  1006. printf("del_node key = %ld, suc_node key = %ld\n",
  1007. rec_del_node.key.ashare, rec_suc_node.key.ashare);
  1008. printf("flag_s = %d\n", ret_struct.F_ss.bshare);
  1009. Node del_node = A[ret_struct.N_d];
  1010. Node suc_node = A[ret_struct.N_s];
  1011. RegAS zero_as; RegXS zero_xs;
  1012. // Update root if needed
  1013. mpc_select(tio, yield, root, ret_struct.F_r, root, ret_struct.ret_ptr);
  1014. bool rec_F_ss = reconstruct_RegBS(tio, yield, ret_struct.F_ss);
  1015. size_t rec_del_key = reconstruct_RegAS(tio, yield, del_node.key);
  1016. size_t rec_suc_key = reconstruct_RegAS(tio, yield, suc_node.key);
  1017. printf("rec_F_ss = %d, del_node.key = %lu, suc_nod.key = %lu\n",
  1018. rec_F_ss, rec_del_key, rec_suc_key);
  1019. mpc_select(tio, yield, del_node.key, ret_struct.F_ss, del_node.key, suc_node.key);
  1020. mpc_select(tio, yield, del_node.value, ret_struct.F_ss, del_node.value, suc_node.value);
  1021. A[ret_struct.N_d].NODE_KEY = del_node.key;
  1022. A[ret_struct.N_d].NODE_VALUE = del_node.value;
  1023. A[ret_struct.N_s].NODE_KEY = zero_as;
  1024. A[ret_struct.N_s].NODE_VALUE = zero_xs;
  1025. RegXS empty_loc;
  1026. mpc_select(tio, yield, empty_loc, ret_struct.F_ss, ret_struct.N_d, ret_struct.N_s);
  1027. //Add deleted (empty) location into the empty_locations vector for reuse in next insert()
  1028. empty_locations.emplace_back(empty_loc);
  1029. }
  1030. return 1;
  1031. }
  1032. }
  1033. // Now we use the AVL class in various ways. This function is called by
  1034. // online.cpp.
  1035. void avl(MPCIO &mpcio,
  1036. const PRACOptions &opts, char **args)
  1037. {
  1038. nbits_t depth=4;
  1039. if (*args) {
  1040. depth = atoi(*args);
  1041. ++args;
  1042. }
  1043. size_t items = (size_t(1)<<depth)-1;
  1044. if (*args) {
  1045. items = atoi(*args);
  1046. ++args;
  1047. }
  1048. MPCTIO tio(mpcio, 0, opts.num_threads);
  1049. run_coroutines(tio, [&tio, depth, items] (yield_t &yield) {
  1050. size_t size = size_t(1)<<depth;
  1051. AVL tree(tio.player(), size);
  1052. // Insert a few elements
  1053. int insert_array[] = {10, 10, 13, 11, 14, 8, 15, 20, 17, 19, 7, 12};
  1054. size_t insert_array_size = 11;
  1055. //int insert_array[] = {10, 10, 13, 11, 14, 8, 15, 20, 17, 19, 7, 12};
  1056. //size_t insert_array_size = 11;
  1057. //int insert_array[] = {6, 3, 10, 1, 2};
  1058. //size_t insert_array_size = 4;
  1059. Node node;
  1060. for(size_t i = 0; i<=insert_array_size; i++) {
  1061. newnode(node);
  1062. node.key.set(insert_array[i] * tio.player());
  1063. printf("Insert %d\n", insert_array[i]);
  1064. tree.insert(tio, yield, node);
  1065. tree.print_oram(tio, yield);
  1066. tree.pretty_print(tio, yield);
  1067. tree.check_avl(tio, yield);
  1068. }
  1069. RegAS del_key;
  1070. del_key.set(10 * tio.player());
  1071. printf("Delete 10\n");
  1072. tree.del(tio, yield, del_key);
  1073. tree.print_oram(tio, yield);
  1074. tree.pretty_print(tio, yield);
  1075. tree.check_avl(tio, yield);
  1076. del_key.set(14 * tio.player());
  1077. printf("Delete 14\n");
  1078. tree.del(tio, yield, del_key);
  1079. tree.print_oram(tio, yield);
  1080. tree.pretty_print(tio, yield);
  1081. tree.check_avl(tio, yield);
  1082. tree.pretty_print(tio, yield);
  1083. del_key.set(12 * tio.player());
  1084. printf("Delete 12\n");
  1085. tree.del(tio, yield, del_key);
  1086. tree.print_oram(tio, yield);
  1087. tree.pretty_print(tio, yield);
  1088. tree.check_avl(tio, yield);
  1089. RegAS lookup_key;
  1090. Node lookup;
  1091. bool success;
  1092. lookup_key.set(8 * tio.player());
  1093. success = tree.lookup(tio, yield, lookup_key, &lookup);
  1094. if(success) {
  1095. printf("Lookup 8 success\n");
  1096. }
  1097. else {
  1098. printf("Lookup 8 failed\n");
  1099. }
  1100. lookup_key.set(12 * tio.player());
  1101. success = tree.lookup(tio, yield, lookup_key, &lookup);
  1102. if(success) {
  1103. printf("Lookup 12 success\n");
  1104. }
  1105. else {
  1106. printf("Lookup 12 failed\n");
  1107. }
  1108. });
  1109. }
  1110. void avl_tests(MPCIO &mpcio,
  1111. const PRACOptions &opts, char **args)
  1112. {
  1113. // Not taking arguments for tests
  1114. nbits_t depth=4;
  1115. size_t items = (size_t(1)<<depth)-1;
  1116. MPCTIO tio(mpcio, 0, opts.num_threads);
  1117. run_coroutines(tio, [&tio, depth, items] (yield_t &yield) {
  1118. size_t size = size_t(1)<<depth;
  1119. bool player0 = tio.player()==0;
  1120. // (T1) : Test 1 : L rotation (root modified)
  1121. /*
  1122. Operation:
  1123. 5 7
  1124. \ / \
  1125. 7 ---> 5 9
  1126. \
  1127. 9
  1128. T1 checks:
  1129. - root is 7
  1130. - 5,7,9 in correct positions
  1131. - 5 and 9 have no children and 0 balances
  1132. */
  1133. {
  1134. AVL tree(tio.player(), size);
  1135. bool success = 1;
  1136. int insert_array[] = {5, 7, 9};
  1137. size_t insert_array_size = 2;
  1138. Node node;
  1139. for(size_t i = 0; i<=insert_array_size; i++) {
  1140. newnode(node);
  1141. node.key.set(insert_array[i] * tio.player());
  1142. tree.insert(tio, yield, node);
  1143. tree.check_avl(tio, yield);
  1144. }
  1145. Duoram<Node>* oram = tree.get_oram();
  1146. RegXS root_xs = tree.get_root();
  1147. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1148. auto A = oram->flat(tio, yield);
  1149. auto R = A.reconstruct();
  1150. Node root_node, left_node, right_node;
  1151. size_t left_index, right_index;
  1152. root_node = R[root];
  1153. if((root_node.key).share()!=7) {
  1154. success = false;
  1155. }
  1156. left_index = (getAVLLeftPtr(root_node.pointers)).share();
  1157. right_index = (getAVLRightPtr(root_node.pointers)).share();
  1158. left_node = R[left_index];
  1159. right_node = R[right_index];
  1160. if(left_node.key.share()!=5 || right_node.key.share()!=9) {
  1161. success = false;
  1162. }
  1163. //To check that left and right have no children and 0 balances
  1164. size_t sum = left_node.pointers.share() + right_node.pointers.share();
  1165. if(sum!=0) {
  1166. success = false;
  1167. }
  1168. if(player0) {
  1169. if(success) {
  1170. print_green("T1 : SUCCESS\n");
  1171. } else {
  1172. print_red("T1 : FAIL\n");
  1173. }
  1174. }
  1175. }
  1176. // (T2) : Test 2 : L rotation (root unmodified)
  1177. /*
  1178. Operation:
  1179. 5 5
  1180. / \ / \
  1181. 3 7 3 9
  1182. \ ---> / \
  1183. 9 7 7 12
  1184. \
  1185. 12
  1186. T2 checks:
  1187. - root is 5
  1188. - 3, 7, 9, 12 in expected positions
  1189. - Nodes 3, 7, 12 have 0 balance and no children
  1190. - 5's bal = 0 1
  1191. */
  1192. {
  1193. AVL tree(tio.player(), size);
  1194. bool success = 1;
  1195. int insert_array[] = {5, 3, 7, 9, 12};
  1196. size_t insert_array_size = 4;
  1197. Node node;
  1198. for(size_t i = 0; i<=insert_array_size; i++) {
  1199. newnode(node);
  1200. node.key.set(insert_array[i] * tio.player());
  1201. tree.insert(tio, yield, node);
  1202. tree.check_avl(tio, yield);
  1203. }
  1204. Duoram<Node>* oram = tree.get_oram();
  1205. RegXS root_xs = tree.get_root();
  1206. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1207. auto A = oram->flat(tio, yield);
  1208. auto R = A.reconstruct();
  1209. Node root_node, n3, n7, n9, n12;
  1210. size_t n3_index, n7_index, n9_index, n12_index;
  1211. root_node = R[root];
  1212. if((root_node.key).share()!=5) {
  1213. success = false;
  1214. }
  1215. n3_index = (getAVLLeftPtr(root_node.pointers)).share();
  1216. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  1217. n3 = R[n3_index];
  1218. n9 = R[n9_index];
  1219. n7_index = getAVLLeftPtr(n9.pointers).share();
  1220. n12_index = getAVLRightPtr(n9.pointers).share();
  1221. n7 = R[n7_index];
  1222. n12 = R[n12_index];
  1223. // Node value checks
  1224. if(n3.key.share()!=3 || n9.key.share()!=9) {
  1225. success = false;
  1226. }
  1227. if(n7.key.share()!=7 || n12.key.share()!=12) {
  1228. success = false;
  1229. }
  1230. // Node children and balance checks
  1231. size_t zero = 0;
  1232. zero+=(n3.pointers.share());
  1233. zero+=(n7.pointers.share());
  1234. zero+=(n12.pointers.share());
  1235. zero+=(getLeftBal(root_node.pointers).share());
  1236. zero+=(getLeftBal(n9.pointers).share());
  1237. zero+=(getRightBal(n9.pointers).share());
  1238. if(zero!=0) {
  1239. success = false;
  1240. }
  1241. int one = (getRightBal(root_node.pointers).share());
  1242. if(one!=1) {
  1243. success = false;
  1244. }
  1245. if(player0) {
  1246. if(success) {
  1247. print_green("T2 : SUCCESS\n");
  1248. } else {
  1249. print_red("T2 : FAIL\n");
  1250. }
  1251. }
  1252. }
  1253. // (T3) : Test 3 : R rotation (root modified)
  1254. /*
  1255. Operation:
  1256. 9 7
  1257. / / \
  1258. 7 ---> 5 9
  1259. /
  1260. 5
  1261. T3 checks:
  1262. - root is 7
  1263. - 5,7,9 in correct positions
  1264. - 5 and 9 have no children
  1265. */
  1266. {
  1267. AVL tree(tio.player(), size);
  1268. bool success = 1;
  1269. int insert_array[] = {9, 7, 5};
  1270. size_t insert_array_size = 2;
  1271. Node node;
  1272. for(size_t i = 0; i<=insert_array_size; i++) {
  1273. newnode(node);
  1274. node.key.set(insert_array[i] * tio.player());
  1275. tree.insert(tio, yield, node);
  1276. tree.check_avl(tio, yield);
  1277. }
  1278. Duoram<Node>* oram = tree.get_oram();
  1279. RegXS root_xs = tree.get_root();
  1280. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1281. auto A = oram->flat(tio, yield);
  1282. auto R = A.reconstruct();
  1283. Node root_node, left_node, right_node;
  1284. size_t left_index, right_index;
  1285. root_node = R[root];
  1286. if((root_node.key).share()!=7) {
  1287. success = false;
  1288. }
  1289. left_index = (getAVLLeftPtr(root_node.pointers)).share();
  1290. right_index = (getAVLRightPtr(root_node.pointers)).share();
  1291. left_node = R[left_index];
  1292. right_node = R[right_index];
  1293. if(left_node.key.share()!=5 || right_node.key.share()!=9) {
  1294. success = false;
  1295. }
  1296. //To check that left and right have no children and 0 balances
  1297. size_t sum = left_node.pointers.share() + right_node.pointers.share();
  1298. if(sum!=0) {
  1299. success = false;
  1300. }
  1301. if(player0) {
  1302. if(success) {
  1303. print_green("T3 : SUCCESS\n");
  1304. } else{
  1305. print_red("T3 : FAIL\n");
  1306. }
  1307. }
  1308. }
  1309. // (T4) : Test 4 : R rotation (root unmodified)
  1310. /*
  1311. Operation:
  1312. 9 9
  1313. / \ / \
  1314. 7 12 5 12
  1315. / ---> / \
  1316. 5 7 3 7
  1317. /
  1318. 3
  1319. T4 checks:
  1320. - root is 9
  1321. - 3,5,7,12 are in correct positions
  1322. - Nodes 3,7,12 have 0 balance
  1323. - Nodes 3,7,12 have no children
  1324. - 9's bal = 1 0
  1325. */
  1326. {
  1327. AVL tree(tio.player(), size);
  1328. bool success = 1;
  1329. int insert_array[] = {9, 12, 7, 5, 3};
  1330. size_t insert_array_size = 4;
  1331. Node node;
  1332. for(size_t i = 0; i<=insert_array_size; i++) {
  1333. newnode(node);
  1334. node.key.set(insert_array[i] * tio.player());
  1335. tree.insert(tio, yield, node);
  1336. tree.check_avl(tio, yield);
  1337. }
  1338. Duoram<Node>* oram = tree.get_oram();
  1339. RegXS root_xs = tree.get_root();
  1340. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1341. auto A = oram->flat(tio, yield);
  1342. auto R = A.reconstruct();
  1343. Node root_node, n3, n7, n5, n12;
  1344. size_t n3_index, n7_index, n5_index, n12_index;
  1345. root_node = R[root];
  1346. if((root_node.key).share()!=9) {
  1347. success = false;
  1348. }
  1349. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  1350. n12_index = (getAVLRightPtr(root_node.pointers)).share();
  1351. n5 = R[n5_index];
  1352. n12 = R[n12_index];
  1353. n3_index = getAVLLeftPtr(n5.pointers).share();
  1354. n7_index = getAVLRightPtr(n5.pointers).share();
  1355. n7 = R[n7_index];
  1356. n3 = R[n3_index];
  1357. // Node value checks
  1358. if(n12.key.share()!=12 || n5.key.share()!=5) {
  1359. success = false;
  1360. }
  1361. if(n3.key.share()!=3 || n7.key.share()!=7) {
  1362. success = false;
  1363. }
  1364. // Node balance checks
  1365. size_t zero = 0;
  1366. zero+=(n3.pointers.share());
  1367. zero+=(n7.pointers.share());
  1368. zero+=(n12.pointers.share());
  1369. zero+=(getRightBal(root_node.pointers).share());
  1370. zero+=(getLeftBal(n5.pointers).share());
  1371. zero+=(getRightBal(n5.pointers).share());
  1372. if(zero!=0) {
  1373. success = false;
  1374. }
  1375. int one = (getLeftBal(root_node.pointers).share());
  1376. if(one!=1) {
  1377. success = false;
  1378. }
  1379. if(player0) {
  1380. if(success) {
  1381. print_green("T4 : SUCCESS\n");
  1382. } else {
  1383. print_red("T4 : FAIL\n");
  1384. }
  1385. }
  1386. }
  1387. // (T5) : Test 5 : LR rotation (root modified)
  1388. /*
  1389. Operation:
  1390. 9 9 7
  1391. / / / \
  1392. 5 --> 7 --> 5 9
  1393. \ /
  1394. 7 5
  1395. T5 checks:
  1396. - root is 7
  1397. - 9,5,7 are in correct positions
  1398. - Nodes 5,7,9 have 0 balance
  1399. - Nodes 5,9 have no children
  1400. */
  1401. {
  1402. AVL tree(tio.player(), size);
  1403. bool success = 1;
  1404. int insert_array[] = {9, 5, 7};
  1405. size_t insert_array_size = 2;
  1406. Node node;
  1407. for(size_t i = 0; i<=insert_array_size; i++) {
  1408. newnode(node);
  1409. node.key.set(insert_array[i] * tio.player());
  1410. tree.insert(tio, yield, node);
  1411. tree.check_avl(tio, yield);
  1412. }
  1413. Duoram<Node>* oram = tree.get_oram();
  1414. RegXS root_xs = tree.get_root();
  1415. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1416. auto A = oram->flat(tio, yield);
  1417. auto R = A.reconstruct();
  1418. Node root_node, n9, n5;
  1419. size_t n9_index, n5_index;
  1420. root_node = R[root];
  1421. if((root_node.key).share()!=7) {
  1422. success = false;
  1423. }
  1424. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  1425. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  1426. n5 = R[n5_index];
  1427. n9 = R[n9_index];
  1428. // Node value checks
  1429. if(n9.key.share()!=9 || n5.key.share()!=5) {
  1430. success = false;
  1431. }
  1432. // Node balance checks
  1433. size_t zero = 0;
  1434. zero+=(n5.pointers.share());
  1435. zero+=(n9.pointers.share());
  1436. zero+=(getRightBal(root_node.pointers).share());
  1437. zero+=(getLeftBal(n5.pointers).share());
  1438. zero+=(getRightBal(n5.pointers).share());
  1439. zero+=(getLeftBal(n5.pointers).share());
  1440. zero+=(getRightBal(n9.pointers).share());
  1441. zero+=(getLeftBal(n9.pointers).share());
  1442. if(zero!=0) {
  1443. success = false;
  1444. }
  1445. if(player0) {
  1446. if(success) {
  1447. print_green("T5 : SUCCESS\n");
  1448. } else {
  1449. print_red("T5 : FAIL\n");
  1450. }
  1451. }
  1452. }
  1453. // (T6) : Test 6 : LR rotation (root unmodified)
  1454. /*
  1455. Operation:
  1456. 9 9 9
  1457. / \ / \ / \
  1458. 7 12 7 12 5 12
  1459. / ---> / ---> / \
  1460. 3 5 3 7
  1461. \ /
  1462. 5 3
  1463. T6 checks:
  1464. - root is 9
  1465. - 3,5,7,12 are in correct positions
  1466. - Nodes 3,7,12 have 0 balance
  1467. - Nodes 3,7,12 have no children
  1468. - 9's bal = 1 0
  1469. */
  1470. {
  1471. AVL tree(tio.player(), size);
  1472. bool success = 1;
  1473. int insert_array[] = {9, 12, 7, 3, 5};
  1474. size_t insert_array_size = 4;
  1475. Node node;
  1476. for(size_t i = 0; i<=insert_array_size; i++) {
  1477. newnode(node);
  1478. node.key.set(insert_array[i] * tio.player());
  1479. tree.insert(tio, yield, node);
  1480. tree.check_avl(tio, yield);
  1481. }
  1482. Duoram<Node>* oram = tree.get_oram();
  1483. RegXS root_xs = tree.get_root();
  1484. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1485. auto A = oram->flat(tio, yield);
  1486. auto R = A.reconstruct();
  1487. Node root_node, n3, n7, n5, n12;
  1488. size_t n3_index, n7_index, n5_index, n12_index;
  1489. root_node = R[root];
  1490. if((root_node.key).share()!=9) {
  1491. success = false;
  1492. }
  1493. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  1494. n12_index = (getAVLRightPtr(root_node.pointers)).share();
  1495. n5 = R[n5_index];
  1496. n12 = R[n12_index];
  1497. n3_index = getAVLLeftPtr(n5.pointers).share();
  1498. n7_index = getAVLRightPtr(n5.pointers).share();
  1499. n7 = R[n7_index];
  1500. n3 = R[n3_index];
  1501. // Node value checks
  1502. if(n5.key.share()!=5 || n12.key.share()!=12) {
  1503. success = false;
  1504. }
  1505. if(n3.key.share()!=3 || n7.key.share()!=7) {
  1506. success = false;
  1507. }
  1508. // Node balance checks
  1509. size_t zero = 0;
  1510. zero+=(n3.pointers.share());
  1511. zero+=(n7.pointers.share());
  1512. zero+=(n12.pointers.share());
  1513. zero+=(getRightBal(root_node.pointers).share());
  1514. zero+=(getLeftBal(n5.pointers).share());
  1515. zero+=(getRightBal(n5.pointers).share());
  1516. if(zero!=0) {
  1517. success = false;
  1518. }
  1519. int one = (getLeftBal(root_node.pointers).share());
  1520. if(one!=1) {
  1521. success = false;
  1522. }
  1523. if(player0) {
  1524. if(success) {
  1525. print_green("T6 : SUCCESS\n");
  1526. } else {
  1527. print_red("T6 : FAIL\n");
  1528. }
  1529. }
  1530. }
  1531. // (T7) : Test 7 : RL rotation (root modified)
  1532. /*
  1533. Operation:
  1534. 5 5 7
  1535. \ \ / \
  1536. 9 --> 7 --> 5 9
  1537. / \
  1538. 7 9
  1539. T7 checks:
  1540. - root is 7
  1541. - 9,5,7 are in correct positions
  1542. - Nodes 5,7,9 have 0 balance
  1543. - Nodes 5,9 have no children
  1544. */
  1545. {
  1546. AVL tree(tio.player(), size);
  1547. bool success = 1;
  1548. int insert_array[] = {5, 9, 7};
  1549. size_t insert_array_size = 2;
  1550. Node node;
  1551. for(size_t i = 0; i<=insert_array_size; i++) {
  1552. newnode(node);
  1553. node.key.set(insert_array[i] * tio.player());
  1554. tree.insert(tio, yield, node);
  1555. tree.check_avl(tio, yield);
  1556. }
  1557. Duoram<Node>* oram = tree.get_oram();
  1558. RegXS root_xs = tree.get_root();
  1559. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1560. auto A = oram->flat(tio, yield);
  1561. auto R = A.reconstruct();
  1562. Node root_node, n9, n5;
  1563. size_t n9_index, n5_index;
  1564. root_node = R[root];
  1565. if((root_node.key).share()!=7) {
  1566. success = false;
  1567. }
  1568. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  1569. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  1570. n5 = R[n5_index];
  1571. n9 = R[n9_index];
  1572. // Node value checks
  1573. if(n9.key.share()!=9 || n5.key.share()!=5) {
  1574. success = false;
  1575. }
  1576. // Node balance checks
  1577. size_t zero = 0;
  1578. zero+=(n5.pointers.share());
  1579. zero+=(n9.pointers.share());
  1580. zero+=(getRightBal(root_node.pointers).share());
  1581. zero+=(getLeftBal(n5.pointers).share());
  1582. zero+=(getRightBal(n5.pointers).share());
  1583. zero+=(getLeftBal(n5.pointers).share());
  1584. zero+=(getRightBal(n9.pointers).share());
  1585. zero+=(getLeftBal(n9.pointers).share());
  1586. if(zero!=0) {
  1587. success = false;
  1588. }
  1589. if(player0) {
  1590. if(success) {
  1591. print_green("T7 : SUCCESS\n");
  1592. } else {
  1593. print_red("T7 : FAIL\n");
  1594. }
  1595. }
  1596. }
  1597. // (T8) : Test 8 : RL rotation (root unmodified)
  1598. /*
  1599. Operation:
  1600. 5 5 5
  1601. / \ / \ / \
  1602. 3 12 3 12 3 9
  1603. / ---> / ---> / \
  1604. 7 9 7 12
  1605. \ /
  1606. 9 7
  1607. T8 checks:
  1608. - root is 5
  1609. - 3,9,7,12 are in correct positions
  1610. - Nodes 3,7,12 have 0 balance
  1611. - Nodes 3,7,12 have no children
  1612. - 5's bal = 0 1
  1613. */
  1614. {
  1615. AVL tree(tio.player(), size);
  1616. bool success = 1;
  1617. int insert_array[] = {5, 3, 12, 7, 9};
  1618. size_t insert_array_size = 4;
  1619. Node node;
  1620. for(size_t i = 0; i<=insert_array_size; i++) {
  1621. newnode(node);
  1622. node.key.set(insert_array[i] * tio.player());
  1623. tree.insert(tio, yield, node);
  1624. tree.check_avl(tio, yield);
  1625. }
  1626. Duoram<Node>* oram = tree.get_oram();
  1627. RegXS root_xs = tree.get_root();
  1628. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1629. auto A = oram->flat(tio, yield);
  1630. auto R = A.reconstruct();
  1631. Node root_node, n3, n7, n9, n12;
  1632. size_t n3_index, n7_index, n9_index, n12_index;
  1633. root_node = R[root];
  1634. if((root_node.key).share()!=5) {
  1635. success = false;
  1636. }
  1637. n3_index = (getAVLLeftPtr(root_node.pointers)).share();
  1638. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  1639. n3 = R[n3_index];
  1640. n9 = R[n9_index];
  1641. n7_index = getAVLLeftPtr(n9.pointers).share();
  1642. n12_index = getAVLRightPtr(n9.pointers).share();
  1643. n7 = R[n7_index];
  1644. n12 = R[n12_index];
  1645. // Node value checks
  1646. if(n3.key.share()!=3 || n9.key.share()!=9) {
  1647. success = false;
  1648. }
  1649. if(n7.key.share()!=7 || n12.key.share()!=12) {
  1650. success = false;
  1651. }
  1652. // Node balance checks
  1653. size_t zero = 0;
  1654. zero+=(n3.pointers.share());
  1655. zero+=(n7.pointers.share());
  1656. zero+=(n12.pointers.share());
  1657. zero+=(getLeftBal(root_node.pointers).share());
  1658. zero+=(getLeftBal(n9.pointers).share());
  1659. zero+=(getRightBal(n9.pointers).share());
  1660. if(zero!=0) {
  1661. success = false;
  1662. }
  1663. int one = (getRightBal(root_node.pointers).share());
  1664. if(one!=1) {
  1665. success = false;
  1666. }
  1667. if(player0) {
  1668. if(success) {
  1669. print_green("T8 : SUCCESS\n");
  1670. } else {
  1671. print_red("T8 : FAIL\n");
  1672. }
  1673. }
  1674. }
  1675. // Deletion Tests:
  1676. // (T9) : Test 9 : L rotation (root modified)
  1677. /*
  1678. Operation:
  1679. 5 7
  1680. / \ Del 3 / \
  1681. 3 7 ------> 5 9
  1682. \
  1683. 9
  1684. T9 checks:
  1685. - root is 7
  1686. - 5,7,9 in correct positions
  1687. - 5 and 9 have no children and 0 balances
  1688. - 7 has 0 balances
  1689. */
  1690. {
  1691. AVL tree(tio.player(), size);
  1692. bool success = 1;
  1693. int insert_array[] = {5, 3, 7, 9};
  1694. size_t insert_array_size = 3;
  1695. Node node;
  1696. for(size_t i = 0; i<=insert_array_size; i++) {
  1697. newnode(node);
  1698. node.key.set(insert_array[i] * tio.player());
  1699. tree.insert(tio, yield, node);
  1700. tree.check_avl(tio, yield);
  1701. }
  1702. RegAS del_key;
  1703. del_key.set(3 * tio.player());
  1704. tree.del(tio, yield, del_key);
  1705. tree.check_avl(tio, yield);
  1706. Duoram<Node>* oram = tree.get_oram();
  1707. RegXS root_xs = tree.get_root();
  1708. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1709. auto A = oram->flat(tio, yield);
  1710. auto R = A.reconstruct();
  1711. Node root_node, left_node, right_node;
  1712. size_t left_index, right_index;
  1713. root_node = R[root];
  1714. if((root_node.key).share()!=7) {
  1715. success = false;
  1716. }
  1717. left_index = (getAVLLeftPtr(root_node.pointers)).share();
  1718. right_index = (getAVLRightPtr(root_node.pointers)).share();
  1719. left_node = R[left_index];
  1720. right_node = R[right_index];
  1721. if(left_node.key.share()!=5 || right_node.key.share()!=9) {
  1722. success = false;
  1723. }
  1724. //To check that left and right have no children and 0 balances
  1725. size_t sum = left_node.pointers.share() + right_node.pointers.share();
  1726. if(sum!=0) {
  1727. success = false;
  1728. }
  1729. if(player0) {
  1730. if(success) {
  1731. print_green("T9 : SUCCESS\n");
  1732. } else {
  1733. print_red("T9 : FAIL\n");
  1734. }
  1735. }
  1736. }
  1737. // (T10) : Test 10 : L rotation (root unmodified)
  1738. /*
  1739. Operation:
  1740. 5 5
  1741. / \ / \
  1742. 3 7 Del 6 3 9
  1743. / / \ ------> / / \
  1744. 1 6 9 1 7 12
  1745. \
  1746. 12
  1747. T10 checks:
  1748. - root is 5
  1749. - 3, 7, 9, 12 in expected positions
  1750. - Nodes 3, 7, 12 have 0 balance and no children
  1751. - 5's bal = 0 1
  1752. */
  1753. {
  1754. AVL tree(tio.player(), size);
  1755. bool success = 1;
  1756. int insert_array[] = {5, 3, 7, 9, 6, 1, 12};
  1757. size_t insert_array_size = 6;
  1758. Node node;
  1759. for(size_t i = 0; i<=insert_array_size; i++) {
  1760. newnode(node);
  1761. node.key.set(insert_array[i] * tio.player());
  1762. tree.insert(tio, yield, node);
  1763. tree.check_avl(tio, yield);
  1764. }
  1765. RegAS del_key;
  1766. del_key.set(6 * tio.player());
  1767. tree.del(tio, yield, del_key);
  1768. tree.check_avl(tio, yield);
  1769. Duoram<Node>* oram = tree.get_oram();
  1770. RegXS root_xs = tree.get_root();
  1771. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1772. auto A = oram->flat(tio, yield);
  1773. auto R = A.reconstruct();
  1774. Node root_node, n1, n3, n7, n9, n12;
  1775. size_t n1_index, n3_index, n7_index, n9_index, n12_index;
  1776. root_node = R[root];
  1777. if((root_node.key).share()!=5) {
  1778. success = false;
  1779. }
  1780. n3_index = (getAVLLeftPtr(root_node.pointers)).share();
  1781. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  1782. n3 = R[n3_index];
  1783. n9 = R[n9_index];
  1784. n7_index = getAVLLeftPtr(n9.pointers).share();
  1785. n12_index = getAVLRightPtr(n9.pointers).share();
  1786. n7 = R[n7_index];
  1787. n12 = R[n12_index];
  1788. n1_index = getAVLLeftPtr(n3.pointers).share();
  1789. n1 = R[n1_index];
  1790. // Node value checks
  1791. if(n3.key.share()!=3 || n9.key.share()!=9) {
  1792. success = false;
  1793. }
  1794. if(n7.key.share()!=7 || n12.key.share()!=12 || n1.key.share()!=1) {
  1795. success = false;
  1796. }
  1797. // Node children and balance checks
  1798. size_t zero = 0;
  1799. zero+=(n1.pointers.share());
  1800. zero+=(n7.pointers.share());
  1801. zero+=(n12.pointers.share());
  1802. zero+=(getLeftBal(root_node.pointers).share());
  1803. zero+=(getRightBal(root_node.pointers).share());
  1804. zero+=(getLeftBal(n9.pointers).share());
  1805. zero+=(getRightBal(n9.pointers).share());
  1806. zero+=(getRightBal(n3.pointers).share());
  1807. if(zero!=0) {
  1808. success = false;
  1809. }
  1810. int one = (getLeftBal(n3.pointers).share());
  1811. if(one!=1) {
  1812. success = false;
  1813. }
  1814. if(player0) {
  1815. if(success) {
  1816. print_green("T10 : SUCCESS\n");
  1817. } else {
  1818. print_red("T10 : FAIL\n");
  1819. }
  1820. }
  1821. }
  1822. // (T11) : Test 11 : R rotation (root modified)
  1823. /*
  1824. Operation:
  1825. 9 7
  1826. / \ Del 12 / \
  1827. 7 12 -------> 5 9
  1828. /
  1829. 5
  1830. T11 checks:
  1831. - root is 7
  1832. - 5,7,9 in correct positions and balances to 0
  1833. - 5 and 9 have no children
  1834. */
  1835. {
  1836. AVL tree(tio.player(), size);
  1837. bool success = 1;
  1838. int insert_array[] = {9, 7, 12, 5};
  1839. size_t insert_array_size = 3;
  1840. Node node;
  1841. for(size_t i = 0; i<=insert_array_size; i++) {
  1842. newnode(node);
  1843. node.key.set(insert_array[i] * tio.player());
  1844. tree.insert(tio, yield, node);
  1845. tree.check_avl(tio, yield);
  1846. }
  1847. RegAS del_key;
  1848. del_key.set(12 * tio.player());
  1849. tree.del(tio, yield, del_key);
  1850. tree.check_avl(tio, yield);
  1851. Duoram<Node>* oram = tree.get_oram();
  1852. RegXS root_xs = tree.get_root();
  1853. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1854. auto A = oram->flat(tio, yield);
  1855. auto R = A.reconstruct();
  1856. Node root_node, left_node, right_node;
  1857. size_t left_index, right_index;
  1858. root_node = R[root];
  1859. if((root_node.key).share()!=7) {
  1860. success = false;
  1861. }
  1862. left_index = (getAVLLeftPtr(root_node.pointers)).share();
  1863. right_index = (getAVLRightPtr(root_node.pointers)).share();
  1864. left_node = R[left_index];
  1865. right_node = R[right_index];
  1866. if(left_node.key.share()!=5 || right_node.key.share()!=9) {
  1867. success = false;
  1868. }
  1869. //To check that left and right have no children and 0 balances
  1870. size_t zero = left_node.pointers.share() + right_node.pointers.share();
  1871. zero+=(getLeftBal(left_node.pointers).share());
  1872. zero+=(getRightBal(left_node.pointers).share());
  1873. zero+=(getLeftBal(right_node.pointers).share());
  1874. zero+=(getRightBal(right_node.pointers).share());
  1875. if(zero!=0) {
  1876. success = false;
  1877. }
  1878. if(player0) {
  1879. if(success) {
  1880. print_green("T11 : SUCCESS\n");
  1881. } else{
  1882. print_red("T11 : FAIL\n");
  1883. }
  1884. }
  1885. }
  1886. // (T12) : Test 12 : R rotation (root unmodified)
  1887. /*
  1888. Operation:
  1889. 9 9
  1890. / \ / \
  1891. 7 12 Del 8 5 12
  1892. / \ \ ------> / \ \
  1893. 5 8 15 3 7 15
  1894. /
  1895. 3
  1896. T4 checks:
  1897. - root is 9
  1898. - 3,5,7,12,15 are in correct positions
  1899. - Nodes 3,7,15 have 0 balance
  1900. - Nodes 3,7,15 have no children
  1901. - 9,5 bal = 0 0
  1902. - 12 bal = 0 1
  1903. */
  1904. {
  1905. AVL tree(tio.player(), size);
  1906. bool success = 1;
  1907. int insert_array[] = {9, 12, 7, 5, 8, 15, 3};
  1908. size_t insert_array_size = 6;
  1909. Node node;
  1910. for(size_t i = 0; i<=insert_array_size; i++) {
  1911. newnode(node);
  1912. node.key.set(insert_array[i] * tio.player());
  1913. tree.insert(tio, yield, node);
  1914. tree.check_avl(tio, yield);
  1915. }
  1916. RegAS del_key;
  1917. del_key.set(8 * tio.player());
  1918. tree.del(tio, yield, del_key);
  1919. tree.check_avl(tio, yield);
  1920. Duoram<Node>* oram = tree.get_oram();
  1921. RegXS root_xs = tree.get_root();
  1922. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  1923. auto A = oram->flat(tio, yield);
  1924. auto R = A.reconstruct();
  1925. Node root_node, n3, n7, n5, n12, n15;
  1926. size_t n3_index, n7_index, n5_index, n12_index, n15_index;
  1927. root_node = R[root];
  1928. if((root_node.key).share()!=9) {
  1929. success = false;
  1930. }
  1931. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  1932. n12_index = (getAVLRightPtr(root_node.pointers)).share();
  1933. n5 = R[n5_index];
  1934. n12 = R[n12_index];
  1935. n3_index = getAVLLeftPtr(n5.pointers).share();
  1936. n7_index = getAVLRightPtr(n5.pointers).share();
  1937. n7 = R[n7_index];
  1938. n3 = R[n3_index];
  1939. n15_index = getAVLRightPtr(n12.pointers).share();
  1940. n15 = R[n15_index];
  1941. // Node value checks
  1942. if(n12.key.share()!=12 || n5.key.share()!=5) {
  1943. success = false;
  1944. }
  1945. if(n3.key.share()!=3 || n7.key.share()!=7 || n15.key.share()!=15) {
  1946. success = false;
  1947. }
  1948. // Node balance checks
  1949. size_t zero = 0;
  1950. zero+=(n3.pointers.share());
  1951. zero+=(n7.pointers.share());
  1952. zero+=(n15.pointers.share());
  1953. zero+=(getRightBal(root_node.pointers).share());
  1954. zero+=(getLeftBal(root_node.pointers).share());
  1955. zero+=(getLeftBal(n5.pointers).share());
  1956. zero+=(getRightBal(n5.pointers).share());
  1957. if(zero!=0) {
  1958. success = false;
  1959. }
  1960. int one = (getRightBal(n12.pointers).share());
  1961. if(one!=1) {
  1962. success = false;
  1963. }
  1964. if(player0) {
  1965. if(success) {
  1966. print_green("T12 : SUCCESS\n");
  1967. } else {
  1968. print_red("T12 : FAIL\n");
  1969. }
  1970. }
  1971. }
  1972. // (T13) : Test 13 : LR rotation (root modified)
  1973. /*
  1974. Operation:
  1975. 9 9 7
  1976. / \ Del 12 / / \
  1977. 5 12 -------> 7 --> 5 9
  1978. \ /
  1979. 7 5
  1980. T5 checks:
  1981. - root is 7
  1982. - 9,5,7 are in correct positions
  1983. - Nodes 5,7,9 have 0 balance
  1984. - Nodes 5,9 have no children
  1985. */
  1986. {
  1987. AVL tree(tio.player(), size);
  1988. bool success = 1;
  1989. int insert_array[] = {9, 5, 12, 7};
  1990. size_t insert_array_size = 3;
  1991. Node node;
  1992. for(size_t i = 0; i<=insert_array_size; i++) {
  1993. newnode(node);
  1994. node.key.set(insert_array[i] * tio.player());
  1995. tree.insert(tio, yield, node);
  1996. tree.check_avl(tio, yield);
  1997. }
  1998. RegAS del_key;
  1999. del_key.set(12 * tio.player());
  2000. tree.del(tio, yield, del_key);
  2001. tree.check_avl(tio, yield);
  2002. Duoram<Node>* oram = tree.get_oram();
  2003. RegXS root_xs = tree.get_root();
  2004. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  2005. auto A = oram->flat(tio, yield);
  2006. auto R = A.reconstruct();
  2007. Node root_node, n9, n5;
  2008. size_t n9_index, n5_index;
  2009. root_node = R[root];
  2010. if((root_node.key).share()!=7) {
  2011. success = false;
  2012. }
  2013. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  2014. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  2015. n5 = R[n5_index];
  2016. n9 = R[n9_index];
  2017. // Node value checks
  2018. if(n9.key.share()!=9 || n5.key.share()!=5) {
  2019. success = false;
  2020. }
  2021. // Node balance checks
  2022. size_t zero = 0;
  2023. zero+=(n5.pointers.share());
  2024. zero+=(n9.pointers.share());
  2025. zero+=(getRightBal(root_node.pointers).share());
  2026. zero+=(getLeftBal(n5.pointers).share());
  2027. zero+=(getRightBal(n5.pointers).share());
  2028. zero+=(getLeftBal(n5.pointers).share());
  2029. zero+=(getRightBal(n9.pointers).share());
  2030. zero+=(getLeftBal(n9.pointers).share());
  2031. if(zero!=0) {
  2032. success = false;
  2033. }
  2034. if(player0) {
  2035. if(success) {
  2036. print_green("T13 : SUCCESS\n");
  2037. } else {
  2038. print_red("T13 : FAIL\n");
  2039. }
  2040. }
  2041. }
  2042. // (T14) : Test 14 : LR rotation (root unmodified)
  2043. /*
  2044. Operation:
  2045. 9 9 9
  2046. / \ / \ / \
  2047. 7 12 Del 8 7 12 5 12
  2048. / \ ------> / ---> / \
  2049. 3 8 5 3 7
  2050. \ /
  2051. 5 3
  2052. T6 checks:
  2053. - root is 9
  2054. - 3,5,7,12 are in correct positions
  2055. - Nodes 3,7,12 have 0 balance
  2056. - Nodes 3,7,12 have no children
  2057. - 9's bal = 1 0
  2058. */
  2059. {
  2060. AVL tree(tio.player(), size);
  2061. bool success = 1;
  2062. int insert_array[] = {9, 12, 7, 3, 5};
  2063. size_t insert_array_size = 4;
  2064. Node node;
  2065. for(size_t i = 0; i<=insert_array_size; i++) {
  2066. newnode(node);
  2067. node.key.set(insert_array[i] * tio.player());
  2068. tree.insert(tio, yield, node);
  2069. tree.check_avl(tio, yield);
  2070. }
  2071. RegAS del_key;
  2072. del_key.set(8 * tio.player());
  2073. tree.del(tio, yield, del_key);
  2074. tree.check_avl(tio, yield);
  2075. Duoram<Node>* oram = tree.get_oram();
  2076. RegXS root_xs = tree.get_root();
  2077. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  2078. auto A = oram->flat(tio, yield);
  2079. auto R = A.reconstruct();
  2080. Node root_node, n3, n7, n5, n12;
  2081. size_t n3_index, n7_index, n5_index, n12_index;
  2082. root_node = R[root];
  2083. if((root_node.key).share()!=9) {
  2084. success = false;
  2085. }
  2086. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  2087. n12_index = (getAVLRightPtr(root_node.pointers)).share();
  2088. n5 = R[n5_index];
  2089. n12 = R[n12_index];
  2090. n3_index = getAVLLeftPtr(n5.pointers).share();
  2091. n7_index = getAVLRightPtr(n5.pointers).share();
  2092. n7 = R[n7_index];
  2093. n3 = R[n3_index];
  2094. // Node value checks
  2095. if(n5.key.share()!=5 || n12.key.share()!=12) {
  2096. success = false;
  2097. }
  2098. if(n3.key.share()!=3 || n7.key.share()!=7) {
  2099. success = false;
  2100. }
  2101. // Node balance checks
  2102. size_t zero = 0;
  2103. zero+=(n3.pointers.share());
  2104. zero+=(n7.pointers.share());
  2105. zero+=(n12.pointers.share());
  2106. zero+=(getRightBal(root_node.pointers).share());
  2107. zero+=(getLeftBal(n5.pointers).share());
  2108. zero+=(getRightBal(n5.pointers).share());
  2109. if(zero!=0) {
  2110. success = false;
  2111. }
  2112. int one = (getLeftBal(root_node.pointers).share());
  2113. if(one!=1) {
  2114. success = false;
  2115. }
  2116. if(player0) {
  2117. if(success) {
  2118. print_green("T14 : SUCCESS\n");
  2119. } else {
  2120. print_red("T14 : FAIL\n");
  2121. }
  2122. }
  2123. }
  2124. // (T15) : Test 15 : RL rotation (root modified)
  2125. /*
  2126. Operation:
  2127. 5 5 7
  2128. / \ Del 3 \ / \
  2129. 3 9 -------> 7 --> 5 9
  2130. / \
  2131. 7 9
  2132. T15 checks:
  2133. - root is 7
  2134. - 9,5,7 are in correct positions
  2135. - Nodes 5,7,9 have 0 balance
  2136. - Nodes 5,9 have no children
  2137. */
  2138. {
  2139. AVL tree(tio.player(), size);
  2140. bool success = 1;
  2141. int insert_array[] = {5, 9, 3, 7};
  2142. size_t insert_array_size = 3;
  2143. Node node;
  2144. for(size_t i = 0; i<=insert_array_size; i++) {
  2145. newnode(node);
  2146. node.key.set(insert_array[i] * tio.player());
  2147. tree.insert(tio, yield, node);
  2148. tree.check_avl(tio, yield);
  2149. }
  2150. RegAS del_key;
  2151. del_key.set(3 * tio.player());
  2152. tree.del(tio, yield, del_key);
  2153. tree.check_avl(tio, yield);
  2154. Duoram<Node>* oram = tree.get_oram();
  2155. RegXS root_xs = tree.get_root();
  2156. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  2157. auto A = oram->flat(tio, yield);
  2158. auto R = A.reconstruct();
  2159. Node root_node, n9, n5;
  2160. size_t n9_index, n5_index;
  2161. root_node = R[root];
  2162. if((root_node.key).share()!=7) {
  2163. success = false;
  2164. }
  2165. n5_index = (getAVLLeftPtr(root_node.pointers)).share();
  2166. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  2167. n5 = R[n5_index];
  2168. n9 = R[n9_index];
  2169. // Node value checks
  2170. if(n9.key.share()!=9 || n5.key.share()!=5) {
  2171. success = false;
  2172. }
  2173. // Node balance checks
  2174. size_t zero = 0;
  2175. zero+=(n5.pointers.share());
  2176. zero+=(n9.pointers.share());
  2177. zero+=(getRightBal(root_node.pointers).share());
  2178. zero+=(getLeftBal(n5.pointers).share());
  2179. zero+=(getRightBal(n5.pointers).share());
  2180. zero+=(getLeftBal(n5.pointers).share());
  2181. zero+=(getRightBal(n9.pointers).share());
  2182. zero+=(getLeftBal(n9.pointers).share());
  2183. if(zero!=0) {
  2184. success = false;
  2185. }
  2186. if(player0) {
  2187. if(success) {
  2188. print_green("T15 : SUCCESS\n");
  2189. } else {
  2190. print_red("T15 : FAIL\n");
  2191. }
  2192. }
  2193. }
  2194. // (T16) : Test 16 : RL rotation (root unmodified)
  2195. /*
  2196. Operation:
  2197. 5 5 5
  2198. / \ / \ / \
  2199. 3 12 Del 1 3 12 3 9
  2200. / / ------> / ---> / \
  2201. 1 7 9 7 12
  2202. \ /
  2203. 9 7
  2204. T8 checks:
  2205. - root is 5
  2206. - 3,9,7,12 are in correct positions
  2207. - Nodes 3,7,12 have 0 balance
  2208. - Nodes 3,7,12 have no children
  2209. - 5's bal = 0 1
  2210. */
  2211. {
  2212. AVL tree(tio.player(), size);
  2213. bool success = 1;
  2214. int insert_array[] = {5, 3, 12, 7, 1, 9};
  2215. size_t insert_array_size = 5;
  2216. Node node;
  2217. for(size_t i = 0; i<=insert_array_size; i++) {
  2218. newnode(node);
  2219. node.key.set(insert_array[i] * tio.player());
  2220. tree.insert(tio, yield, node);
  2221. tree.check_avl(tio, yield);
  2222. }
  2223. RegAS del_key;
  2224. del_key.set(1 * tio.player());
  2225. tree.del(tio, yield, del_key);
  2226. tree.check_avl(tio, yield);
  2227. Duoram<Node>* oram = tree.get_oram();
  2228. RegXS root_xs = tree.get_root();
  2229. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  2230. auto A = oram->flat(tio, yield);
  2231. auto R = A.reconstruct();
  2232. Node root_node, n3, n7, n9, n12;
  2233. size_t n3_index, n7_index, n9_index, n12_index;
  2234. root_node = R[root];
  2235. if((root_node.key).share()!=5) {
  2236. success = false;
  2237. }
  2238. n3_index = (getAVLLeftPtr(root_node.pointers)).share();
  2239. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  2240. n3 = R[n3_index];
  2241. n9 = R[n9_index];
  2242. n7_index = getAVLLeftPtr(n9.pointers).share();
  2243. n12_index = getAVLRightPtr(n9.pointers).share();
  2244. n7 = R[n7_index];
  2245. n12 = R[n12_index];
  2246. // Node value checks
  2247. if(n3.key.share()!=3 || n9.key.share()!=9) {
  2248. success = false;
  2249. }
  2250. if(n7.key.share()!=7 || n12.key.share()!=12) {
  2251. success = false;
  2252. }
  2253. // Node balance checks
  2254. size_t zero = 0;
  2255. zero+=(n3.pointers.share());
  2256. zero+=(n7.pointers.share());
  2257. zero+=(n12.pointers.share());
  2258. zero+=(getLeftBal(root_node.pointers).share());
  2259. zero+=(getLeftBal(n9.pointers).share());
  2260. zero+=(getRightBal(n9.pointers).share());
  2261. if(zero!=0) {
  2262. success = false;
  2263. }
  2264. int one = (getRightBal(root_node.pointers).share());
  2265. if(one!=1) {
  2266. success = false;
  2267. }
  2268. if(player0) {
  2269. if(success) {
  2270. print_green("T16 : SUCCESS\n");
  2271. } else {
  2272. print_red("T16 : FAIL\n");
  2273. }
  2274. }
  2275. }
  2276. // (T17) : Test 17 : Double imbalance (root modified)
  2277. /*
  2278. Operation:
  2279. 9 9
  2280. / \ / \
  2281. 5 12 Del 10 5 15
  2282. / \ / \ --------> / \ / \
  2283. 3 7 10 15 3 7 12 20
  2284. / \ / \ \ / \ / \
  2285. 2 4 6 8 20 2 4 6 8
  2286. / /
  2287. 1 1
  2288. 5
  2289. / \
  2290. 3 9
  2291. -----> / \ / \
  2292. 2 4 7 15
  2293. / / \ / \
  2294. 1 6 8 10 20
  2295. T17 checks:
  2296. - root is 5
  2297. - all other nodes are in correct positions
  2298. - balances and children are correct
  2299. */
  2300. {
  2301. AVL tree(tio.player(), size);
  2302. bool success = 1;
  2303. int insert_array[] = {9, 5, 12, 7, 3, 10, 15, 2, 4, 6, 8, 20, 1};
  2304. size_t insert_array_size = 12;
  2305. Node node;
  2306. for(size_t i = 0; i<=insert_array_size; i++) {
  2307. newnode(node);
  2308. node.key.set(insert_array[i] * tio.player());
  2309. tree.insert(tio, yield, node);
  2310. tree.check_avl(tio, yield);
  2311. }
  2312. RegAS del_key;
  2313. del_key.set(10 * tio.player());
  2314. tree.del(tio, yield, del_key);
  2315. tree.check_avl(tio, yield);
  2316. Duoram<Node>* oram = tree.get_oram();
  2317. RegXS root_xs = tree.get_root();
  2318. size_t root = reconstruct_RegXS(tio, yield, root_xs);
  2319. auto A = oram->flat(tio, yield);
  2320. auto R = A.reconstruct();
  2321. Node root_node, n3, n7, n9;
  2322. Node n1, n2, n4, n6, n8, n12, n15, n20;
  2323. size_t n3_index, n7_index, n9_index;
  2324. size_t n1_index, n2_index, n4_index, n6_index;
  2325. size_t n8_index, n12_index, n15_index, n20_index;
  2326. root_node = R[root];
  2327. if((root_node.key).share()!=5) {
  2328. success = false;
  2329. }
  2330. n3_index = (getAVLLeftPtr(root_node.pointers)).share();
  2331. n9_index = (getAVLRightPtr(root_node.pointers)).share();
  2332. n3 = R[n3_index];
  2333. n9 = R[n9_index];
  2334. n2_index = getAVLLeftPtr(n3.pointers).share();
  2335. n4_index = getAVLRightPtr(n3.pointers).share();
  2336. n7_index = getAVLLeftPtr(n9.pointers).share();
  2337. n15_index = getAVLRightPtr(n9.pointers).share();
  2338. n2 = R[n2_index];
  2339. n4 = R[n4_index];
  2340. n7 = R[n7_index];
  2341. n15 = R[n15_index];
  2342. n1_index = getAVLLeftPtr(n2.pointers).share();
  2343. n6_index = getAVLLeftPtr(n7.pointers).share();
  2344. n8_index = getAVLRightPtr(n7.pointers).share();
  2345. n12_index = getAVLLeftPtr(n15.pointers).share();
  2346. n20_index = getAVLRightPtr(n15.pointers).share();
  2347. n1 = R[n1_index];
  2348. n6 = R[n6_index];
  2349. n8 = R[n8_index];
  2350. n12 = R[n12_index];
  2351. n20 = R[n20_index];
  2352. // Node value checks
  2353. if(n3.key.share()!=3 || n9.key.share()!=9) {
  2354. success = false;
  2355. }
  2356. if(n2.key.share()!=2 || n4.key.share()!=4) {
  2357. success = false;
  2358. }
  2359. if(n7.key.share()!=7 || n15.key.share()!=15) {
  2360. success = false;
  2361. }
  2362. if(n1.key.share()!=1 || n6.key.share()!=6 || n8.key.share()!=8) {
  2363. success = false;
  2364. }
  2365. if(n12.key.share()!=12 || n20.key.share()!=20) {
  2366. success = false;
  2367. }
  2368. // Node balance checks
  2369. size_t zero = 0;
  2370. zero+=(n1.pointers.share());
  2371. zero+=(n4.pointers.share());
  2372. zero+=(n6.pointers.share());
  2373. zero+=(n8.pointers.share());
  2374. zero+=(n12.pointers.share());
  2375. zero+=(n20.pointers.share());
  2376. zero+=(getLeftBal(n7.pointers).share());
  2377. zero+=(getRightBal(n7.pointers).share());
  2378. zero+=(getLeftBal(n9.pointers).share());
  2379. zero+=(getRightBal(n9.pointers).share());
  2380. zero+=(getLeftBal(n15.pointers).share());
  2381. zero+=(getRightBal(n15.pointers).share());
  2382. zero+=(getRightBal(n3.pointers).share());
  2383. zero+=(getLeftBal(root_node.pointers).share());
  2384. zero+=(getRightBal(root_node.pointers).share());
  2385. if(zero!=0) {
  2386. success = false;
  2387. }
  2388. int one = (getLeftBal(n3.pointers).share());
  2389. if(one!=1) {
  2390. success = false;
  2391. }
  2392. if(player0) {
  2393. if(success) {
  2394. print_green("T17 : SUCCESS\n");
  2395. } else {
  2396. print_red("T17 : FAIL\n");
  2397. }
  2398. }
  2399. }
  2400. });
  2401. }