|
@@ -37,8 +37,8 @@ bool reconstruct_RegBS(MPCTIO &tio, yield_t &yield, RegBS flag) {
|
|
|
return reconstructed_flag.bshare;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- A function to assign a new random 8-bit key to a node, and resets its
|
|
|
+/*
|
|
|
+ A function to assign a new random 8-bit key to a node, and resets its
|
|
|
pointers to zeroes. The node is assigned a new random 64-bit value.
|
|
|
*/
|
|
|
static void randomize_node(Node &a) {
|
|
@@ -48,13 +48,13 @@ static void randomize_node(Node &a) {
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- A function to perform key comparsions for BST traversal.
|
|
|
+ A function to perform key comparsions for BST traversal.
|
|
|
Inputs: k1 = key of node in the tree, k2 = insertion/deletion/lookup key.
|
|
|
- Evaluates (k2-k1), and combines the lt and eq flag into one (flag to go
|
|
|
+ Evaluates (k2-k1), and combines the lt and eq flag into one (flag to go
|
|
|
left), and keeps the gt flag as is (flag to go right) during traversal.
|
|
|
-
|
|
|
+
|
|
|
*/
|
|
|
-std::tuple<RegBS, RegBS> compare_keys(MPCTIO tio, yield_t &yield, RegAS k1,
|
|
|
+std::tuple<RegBS, RegBS> compare_keys(MPCTIO tio, yield_t &yield, RegAS k1,
|
|
|
RegAS k2) {
|
|
|
CDPF cdpf = tio.cdpf(yield);
|
|
|
auto [lt, eq, gt] = cdpf.compare(tio, yield, k2 - k1, tio.aes_ops());
|
|
@@ -65,17 +65,17 @@ std::tuple<RegBS, RegBS> compare_keys(MPCTIO tio, yield_t &yield, RegAS k1,
|
|
|
// Assuming pointer of 64 bits is split as:
|
|
|
// - 32 bits Left ptr (L)
|
|
|
// - 32 bits Right ptr (R)
|
|
|
-// The pointers are stored as: (L << 32) | R
|
|
|
+// The pointers are stored as: (L << 32) | R
|
|
|
|
|
|
-inline RegXS extractLeftPtr(RegXS pointer){
|
|
|
- return ((pointer&(0xFFFFFFFF00000000))>>32);
|
|
|
+inline RegXS extractLeftPtr(RegXS pointer){
|
|
|
+ return ((pointer&(0xFFFFFFFF00000000))>>32);
|
|
|
}
|
|
|
|
|
|
inline RegXS extractRightPtr(RegXS pointer){
|
|
|
- return (pointer&(0x00000000FFFFFFFF));
|
|
|
+ return (pointer&(0x00000000FFFFFFFF));
|
|
|
}
|
|
|
|
|
|
-inline void setLeftPtr(RegXS &pointer, RegXS new_ptr){
|
|
|
+inline void setLeftPtr(RegXS &pointer, RegXS new_ptr){
|
|
|
pointer&=(0x00000000FFFFFFFF);
|
|
|
pointer+=(new_ptr<<32);
|
|
|
}
|
|
@@ -207,9 +207,9 @@ void BST::check_bst(MPCTIO &tio, yield_t &yield) {
|
|
|
|
|
|
/*
|
|
|
The recursive insert() call, invoked by the wrapper insert() function.
|
|
|
-
|
|
|
+
|
|
|
Takes as input the pointer to the current node in tree traversal (ptr),
|
|
|
- the new node to be inserted (new_node), the underlying Duoram as a
|
|
|
+ the new node to be inserted (new_node), the underlying Duoram as a
|
|
|
flat (A), and the Time-To_live TTL, and a shared flag (isDummy) which
|
|
|
tracks if the operation is dummy/real.
|
|
|
|
|
@@ -228,10 +228,10 @@ std::tuple<RegXS, RegBS> BST::insert(MPCTIO &tio, yield_t &yield, RegXS ptr,
|
|
|
|
|
|
// Depending on [lteq, gt] select the next ptr/index as
|
|
|
// upper 32 bits of cnode.pointers if lteq
|
|
|
- // lower 32 bits of cnode.pointers if gt
|
|
|
+ // lower 32 bits of cnode.pointers if gt
|
|
|
RegXS left = extractLeftPtr(cnode.pointers);
|
|
|
RegXS right = extractRightPtr(cnode.pointers);
|
|
|
-
|
|
|
+
|
|
|
RegXS next_ptr;
|
|
|
mpc_select(tio, yield, next_ptr, gt, left, right, 32);
|
|
|
|
|
@@ -241,13 +241,13 @@ std::tuple<RegXS, RegBS> BST::insert(MPCTIO &tio, yield_t &yield, RegXS ptr,
|
|
|
RegBS F_z = dpf.is_zero(tio, yield, next_ptr, aes_ops);
|
|
|
RegBS F_i;
|
|
|
|
|
|
- // F_i: If this was last node on path (F_z) && isNotDummy:
|
|
|
+ // F_i: If this was last node on path (F_z) && isNotDummy:
|
|
|
// insert new_node here.
|
|
|
mpc_and(tio, yield, F_i, (isNotDummy), F_z);
|
|
|
-
|
|
|
+
|
|
|
isDummy^=F_i;
|
|
|
auto [wptr, direction] = insert(tio, yield, next_ptr, new_node, A, TTL-1, isDummy);
|
|
|
-
|
|
|
+
|
|
|
RegXS ret_ptr;
|
|
|
RegBS ret_direction;
|
|
|
// If we insert here (F_i), return the ptr to this node as wptr
|
|
@@ -258,7 +258,7 @@ std::tuple<RegXS, RegBS> BST::insert(MPCTIO &tio, yield_t &yield, RegXS ptr,
|
|
|
//ret_direction = direction + F_i (direction - gt)
|
|
|
{ mpc_and(tio, yield, ret_direction, F_i, direction^gt);});
|
|
|
|
|
|
- ret_direction^=direction;
|
|
|
+ ret_direction^=direction;
|
|
|
|
|
|
return {ret_ptr, ret_direction};
|
|
|
}
|
|
@@ -288,7 +288,7 @@ void BST::insert(MPCTIO &tio, yield_t &yield, const Node &node, Duoram<Node>::Fl
|
|
|
bool insertAtEmptyLocation = (empty_locations.size() > 0);
|
|
|
if(insertAtEmptyLocation) {
|
|
|
insert_address = empty_locations.back();
|
|
|
- empty_locations.pop_back();
|
|
|
+ empty_locations.pop_back();
|
|
|
A[insert_address] = node;
|
|
|
} else {
|
|
|
new_id = 1 + num_items;
|
|
@@ -305,14 +305,14 @@ void BST::insert(MPCTIO &tio, yield_t &yield, const Node &node, Duoram<Node>::Fl
|
|
|
RegXS left_ptr = extractLeftPtr(pointers);
|
|
|
RegXS right_ptr = extractRightPtr(pointers);
|
|
|
RegXS new_right_ptr, new_left_ptr;
|
|
|
-
|
|
|
- RegBS not_direction = direction;
|
|
|
+
|
|
|
+ RegBS not_direction = direction;
|
|
|
if (player0) {
|
|
|
not_direction^=1;
|
|
|
}
|
|
|
-
|
|
|
- run_coroutines(tio,
|
|
|
- [&tio, &new_right_ptr, direction, right_ptr, insert_address](yield_t &yield)
|
|
|
+
|
|
|
+ run_coroutines(tio,
|
|
|
+ [&tio, &new_right_ptr, direction, right_ptr, insert_address](yield_t &yield)
|
|
|
{ mpc_select(tio, yield, new_right_ptr, direction, right_ptr, insert_address);},
|
|
|
[&tio, &new_left_ptr, not_direction, left_ptr, insert_address](yield_t &yield)
|
|
|
{ mpc_select(tio, yield, new_left_ptr, not_direction, left_ptr, insert_address);});
|
|
@@ -320,7 +320,7 @@ void BST::insert(MPCTIO &tio, yield_t &yield, const Node &node, Duoram<Node>::Fl
|
|
|
setLeftPtr(pointers, new_left_ptr);
|
|
|
setRightPtr(pointers, new_right_ptr);
|
|
|
A[wptr].NODE_POINTERS = pointers;
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -360,10 +360,10 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS key, Duoram<Node
|
|
|
|
|
|
// Depending on [lteq, gt] select the next ptr/index as
|
|
|
// upper 32 bits of cnode.pointers if lteq
|
|
|
- // lower 32 bits of cnode.pointers if gt
|
|
|
+ // lower 32 bits of cnode.pointers if gt
|
|
|
RegXS left = extractLeftPtr(cnode.pointers);
|
|
|
RegXS right = extractRightPtr(cnode.pointers);
|
|
|
-
|
|
|
+
|
|
|
RegXS next_ptr;
|
|
|
|
|
|
RegBS F_found;
|
|
@@ -371,7 +371,7 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS key, Duoram<Node
|
|
|
// then we found the node to return
|
|
|
RegBS isNotDummy = isDummy ^ (!tio.player());
|
|
|
|
|
|
- // Note: This logic returns the last matched key and value.
|
|
|
+ // Note: This logic returns the last matched key and value.
|
|
|
// Returning the first one incurs an additional round.
|
|
|
std::vector<coro_t> coroutines;
|
|
|
coroutines.emplace_back(
|
|
@@ -391,7 +391,7 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS key, Duoram<Node
|
|
|
{ mpc_or(tio, yield, isDummy, isDummy, eq);});
|
|
|
run_coroutines(tio, coroutines);
|
|
|
|
|
|
- #ifdef BST_DEBUG
|
|
|
+ #ifdef BST_DEBUG
|
|
|
size_t ckey = mpc_reconstruct(tio, yield, cnode.key, 64);
|
|
|
size_t lkey = mpc_reconstruct(tio, yield, key, 64);
|
|
|
bool rec_lt = mpc_reconstruct(tio, yield, lt);
|
|
@@ -402,10 +402,10 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS key, Duoram<Node
|
|
|
printf("rec_lt = %d, rec_eq = %d, rec_gt = %d\n", rec_lt, rec_eq, rec_gt);
|
|
|
printf("rec_isDummy/found = %d ,rec_f_found = %d, cnode.key = %ld, lookup key = %ld\n", rec_found, rec_f_found, ckey, lkey);
|
|
|
#endif
|
|
|
-
|
|
|
+
|
|
|
RegBS found = lookup(tio, yield, next_ptr, key, A, TTL-1, isDummy, ret_node);
|
|
|
|
|
|
- return found;
|
|
|
+ return found;
|
|
|
}
|
|
|
|
|
|
RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegAS key, Node *ret_node) {
|
|
@@ -432,10 +432,10 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegAS key, Node *ret_node) {
|
|
|
|
|
|
/*
|
|
|
The recursive del() call, invoked by the wrapper del() function.
|
|
|
-
|
|
|
+
|
|
|
Takes as input the pointer to the current node in tree traversal (ptr),
|
|
|
- the key to be deleted (del_key), the underlying Duoram as a
|
|
|
- flat (A), Flags af (already found) and fs (find successor), the
|
|
|
+ the key to be deleted (del_key), the underlying Duoram as a
|
|
|
+ flat (A), Flags af (already found) and fs (find successor), the
|
|
|
Time-To_live TTL. Finally, a return structure ret_struct that tracks
|
|
|
the location of the successor node and the node to delete to perform
|
|
|
the actual deletion after the recursive traversal; which is required in
|
|
@@ -446,15 +446,15 @@ RegBS BST::lookup(MPCTIO &tio, yield_t &yield, RegAS key, Node *ret_node) {
|
|
|
*/
|
|
|
|
|
|
bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
- Duoram<Node>::Flat &A, RegBS af, RegBS fs, int TTL,
|
|
|
+ Duoram<Node>::Flat &A, RegBS af, RegBS fs, int TTL,
|
|
|
del_return &ret_struct) {
|
|
|
bool player0 = tio.player()==0;
|
|
|
//printf("TTL = %d\n", TTL);
|
|
|
if(TTL==0) {
|
|
|
//Reconstruct and return af
|
|
|
bool success = reconstruct_RegBS(tio, yield, af);
|
|
|
- //printf("Reconstructed flag = %d\n", success);
|
|
|
- if(player0) {
|
|
|
+ //printf("Reconstructed flag = %d\n", success);
|
|
|
+ if(player0) {
|
|
|
ret_struct.F_r^=1;
|
|
|
}
|
|
|
return success;
|
|
@@ -466,11 +466,11 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
Node node = A[ptr];
|
|
|
RegXS left = extractLeftPtr(node.pointers);
|
|
|
RegXS right = extractRightPtr(node.pointers);
|
|
|
-
|
|
|
+
|
|
|
CDPF cdpf = tio.cdpf(yield);
|
|
|
size_t &aes_ops = tio.aes_ops();
|
|
|
RegBS l0, r0, lt, eq, gt;
|
|
|
- // l0: Is left child 0
|
|
|
+ // l0: Is left child 0
|
|
|
// r0: Is right child 0
|
|
|
run_coroutines(tio,
|
|
|
[&tio, &l0, left, &aes_ops, &cdpf](yield_t &yield)
|
|
@@ -495,7 +495,7 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
printf("cdpf.compare results: lt = %d, eq = %d, gt = %d\n", lt_rec, eq_rec, gt_rec);
|
|
|
*/
|
|
|
|
|
|
- // c is the direction bit for next_ptr
|
|
|
+ // c is the direction bit for next_ptr
|
|
|
// (c=0: go left or c=1: go right)
|
|
|
RegBS c = gt;
|
|
|
// lf = local found. We found the key to delete in this level.
|
|
@@ -507,12 +507,12 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
// F_1 = l0 \xor r0
|
|
|
F_1 = l0 ^ r0;
|
|
|
|
|
|
- // We set next ptr based on c, but we need to handle three
|
|
|
+ // We set next ptr based on c, but we need to handle three
|
|
|
// edge cases where we do not go by just the comparison result
|
|
|
RegXS next_ptr;
|
|
|
RegBS c_prime;
|
|
|
// Case 1: found the node here (lf): we traverse down the lone child path.
|
|
|
- // or we are finding successor (fs) and there is no left child.
|
|
|
+ // or we are finding successor (fs) and there is no left child.
|
|
|
RegBS F_c1, F_c2, F_c3, F_c4;
|
|
|
|
|
|
// Case 1: lf & F_1
|
|
@@ -522,7 +522,7 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
[&tio, &F_0, l0, r0] (yield_t &yield)
|
|
|
// F_0 = l0 & r0
|
|
|
{ mpc_and(tio, yield, F_0, l0, r0);});
|
|
|
-
|
|
|
+
|
|
|
// F_2 = !(F_0 + F_1) (Only 1 of F_0, F_1, and F_2 can be true)
|
|
|
F_2 = F_0 ^ F_1;
|
|
|
if(player0)
|
|
@@ -547,13 +547,13 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
// In find successor case, so find inorder successor
|
|
|
// (Go right and then find leftmost child.)
|
|
|
{ mpc_and(tio, yield, F_c2, lf, F_2);});
|
|
|
-
|
|
|
+
|
|
|
/*
|
|
|
// Reconstruct and Debug Block 2
|
|
|
bool F_c2_rec, s1_rec;
|
|
|
F_c2_rec = mpc_reconstruct(tio, yield, F_c2);
|
|
|
- s1_rec = mpc_reconstruct(tio, yield, s1);
|
|
|
- c_prime_rec = mpc_reconstruct(tio, yield, c_prime);
|
|
|
+ s1_rec = mpc_reconstruct(tio, yield, s1);
|
|
|
+ c_prime_rec = mpc_reconstruct(tio, yield, c_prime);
|
|
|
printf("c_prime = %d, F_c2 = %d, s1 = %d\n", c_prime_rec, F_c2_rec, s1_rec);
|
|
|
*/
|
|
|
|
|
@@ -562,7 +562,7 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
{ mpc_select(tio, yield, c_prime, F_c2, c_prime, s1);},
|
|
|
[&tio, &F_c3, fs, F_2](yield_t &yield)
|
|
|
// Case 3: finding successor (fs) and node has both children (F_2)
|
|
|
- // Go left.
|
|
|
+ // Go left.
|
|
|
{ mpc_and(tio, yield, F_c3, fs, F_2);});
|
|
|
|
|
|
run_coroutines(tio,
|
|
@@ -577,7 +577,7 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
mpc_select(tio, yield, c_prime, F_c4, c_prime, l0);
|
|
|
|
|
|
RegBS af_prime, fs_prime;
|
|
|
- run_coroutines(tio,
|
|
|
+ run_coroutines(tio,
|
|
|
[&tio, &next_ptr, c_prime, left, right](yield_t &yield)
|
|
|
// Set next_ptr
|
|
|
{ mpc_select(tio, yield, next_ptr, c_prime, left, right, 32);},
|
|
@@ -597,7 +597,7 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- //printf("TTL = %d\n", TTL);
|
|
|
+ //printf("TTL = %d\n", TTL);
|
|
|
RegBS F_rs_right, F_rs_left, not_c_prime=c_prime;
|
|
|
if(player0) {
|
|
|
not_c_prime^=1;
|
|
@@ -630,22 +630,22 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
setRightPtr(new_ptr, right);
|
|
|
A[ptr].NODE_POINTERS = new_ptr;
|
|
|
|
|
|
- // Update the return structure
|
|
|
+ // Update the return structure
|
|
|
RegBS F_nd, F_ns, F_r, not_af = af, not_F_2 = F_2;
|
|
|
if(player0) {
|
|
|
not_af^=1;
|
|
|
not_F_2^=1;
|
|
|
}
|
|
|
- // F_ns = fs & l0
|
|
|
+ // F_ns = fs & l0
|
|
|
// Finding successor flag & no more left child = F_c4
|
|
|
F_ns = F_c4;
|
|
|
-
|
|
|
- run_coroutines(tio,
|
|
|
+
|
|
|
+ run_coroutines(tio,
|
|
|
[&tio, &ret_struct, F_c2](yield_t &yield)
|
|
|
{ mpc_or(tio, yield, ret_struct.F_ss, ret_struct.F_ss, F_c2);},
|
|
|
[&tio, &F_nd, lf, not_af](yield_t &yield)
|
|
|
{ mpc_and(tio, yield, F_nd, lf, not_af);});
|
|
|
-
|
|
|
+
|
|
|
|
|
|
// F_r = F_d.(!F_2)
|
|
|
// If we have to delete here, and it doesn't have two children we have to
|
|
@@ -662,13 +662,15 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegXS ptr, RegAS del_key,
|
|
|
[&tio, &ret_struct, F_r, ptr](yield_t &yield)
|
|
|
{ mpc_select(tio, yield, ret_struct.ret_ptr, F_r, ptr, ret_struct.ret_ptr);});
|
|
|
|
|
|
- //We don't empty the key and value of the node with del_key in the ORAM
|
|
|
+ //We don't empty the key and value of the node with del_key in the ORAM
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
The main del() function.
|
|
|
+ Trying to delete an item that does not exist in the tree will result in
|
|
|
+ an explicit (non-oblivious) failure.
|
|
|
|
|
|
Takes as input the key to delete (del_key).
|
|
|
Returns success/fail bit.
|
|
@@ -684,22 +686,22 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegAS del_key) {
|
|
|
empty_locations.emplace_back(root);
|
|
|
A[root] = zero;
|
|
|
num_items--;
|
|
|
- return 1;
|
|
|
+ return 1;
|
|
|
} else {
|
|
|
int TTL = num_items;
|
|
|
// Flags for already found (af) item to delete and find successor (fs)
|
|
|
// if this deletion requires a successor swap
|
|
|
RegBS af;
|
|
|
RegBS fs;
|
|
|
- del_return ret_struct;
|
|
|
+ del_return ret_struct;
|
|
|
auto A = oram.flat(tio, yield);
|
|
|
- int success = del(tio, yield, root, del_key, A, af, fs, TTL, ret_struct);
|
|
|
- printf ("Success = %d\n", success);
|
|
|
+ int success = del(tio, yield, root, del_key, A, af, fs, TTL, ret_struct);
|
|
|
+ printf ("Success = %d\n", success);
|
|
|
if(!success){
|
|
|
return 0;
|
|
|
}
|
|
|
else{
|
|
|
- num_items--;
|
|
|
+ num_items--;
|
|
|
/*
|
|
|
printf("In delete's swap portion\n");
|
|
|
Node del_node = A.reconstruct(A[ret_struct.N_d]);
|
|
@@ -712,8 +714,8 @@ bool BST::del(MPCTIO &tio, yield_t &yield, RegAS del_key) {
|
|
|
Node suc_node = A[ret_struct.N_s];
|
|
|
RegAS zero_as; RegXS zero_xs;
|
|
|
RegXS empty_loc, temp_root = root;
|
|
|
-
|
|
|
- run_coroutines(tio,
|
|
|
+
|
|
|
+ run_coroutines(tio,
|
|
|
[&tio, &temp_root, ret_struct](yield_t &yield)
|
|
|
{ mpc_select(tio, yield, temp_root, ret_struct.F_r, temp_root, ret_struct.ret_ptr);},
|
|
|
[&tio, &del_node, ret_struct, suc_node](yield_t &yield)
|
|
@@ -771,15 +773,15 @@ void bst(MPCIO &mpcio,
|
|
|
int insert_array[] = {10, 10, 13, 11, 14, 8, 15, 20, 17, 19, 7, 12};
|
|
|
//int insert_array[] = {1, 2, 3, 4, 5, 6};
|
|
|
size_t insert_array_size = sizeof(insert_array)/sizeof(int);
|
|
|
- Node node;
|
|
|
+ Node node;
|
|
|
for(size_t i = 0; i<insert_array_size; i++) {
|
|
|
randomize_node(node);
|
|
|
node.key.set(insert_array[i] * tio.player());
|
|
|
tree.insert(tio, yield, node);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
tree.pretty_print(tio, yield);
|
|
|
-
|
|
|
+
|
|
|
RegAS del_key;
|
|
|
|
|
|
printf("\n\nDelete %x\n", 20);
|
|
@@ -863,7 +865,7 @@ void bst(MPCIO &mpcio,
|
|
|
if(rec_found) {
|
|
|
printf("Lookup Success\n");
|
|
|
size_t value = mpc_reconstruct(tio, yield, node.value, 64);
|
|
|
- printf("value = %lx\n", value);
|
|
|
+ printf("value = %lx\n", value);
|
|
|
} else {
|
|
|
printf("Lookup Failed\n");
|
|
|
}
|