Browse Source

ORAM operations now reuse RDPFs when given the same OblivIndex object

Ian Goldberg 1 year ago
parent
commit
167fb6614a
4 changed files with 61 additions and 22 deletions
  1. 5 0
      duoram.hpp
  2. 22 18
      duoram.tcc
  3. 30 3
      online.cpp
  4. 4 1
      rdpf.hpp

+ 5 - 0
duoram.hpp

@@ -464,6 +464,11 @@ public:
         assert(incremental);
         idx.xshare = (idx.xshare << 1) | value_t(bit.bshare);
         ++curdepth;
+        if (player < 2) {
+            dt->depth(curdepth);
+        } else {
+            dp->depth(curdepth);
+        }
     }
 
     // Get a copy of the index

+ 22 - 18
duoram.tcc

@@ -286,7 +286,8 @@ Duoram<T>::Shape::MemRefS<U,FT,FST,Sh,WIDTH>::operator FT()
     if (player < 2) {
         // Computational players do this
 
-        RDPFTriple<1> dt = shape.tio.rdpftriple(shape.yield, shape.addr_size);
+        const RDPFTriple<1> &dt = *(oblividx->dt);
+        const nbits_t depth = dt.depth();
 
         // Compute the index offset
         U indoffset;
@@ -297,17 +298,17 @@ Duoram<T>::Shape::MemRefS<U,FT,FST,Sh,WIDTH>::operator FT()
         RDPF2of3<1> dp(dt, 0, player == 0 ? 2 : 1);
 
         // Send it to the peer and the server
-        shape.tio.queue_peer(&indoffset, BITBYTES(shape.addr_size));
-        shape.tio.queue_server(&indoffset, BITBYTES(shape.addr_size));
+        shape.tio.queue_peer(&indoffset, BITBYTES(depth));
+        shape.tio.queue_server(&indoffset, BITBYTES(depth));
 
         shape.yield();
 
         // Receive the above from the peer
         U peerindoffset;
-        shape.tio.recv_peer(&peerindoffset, BITBYTES(shape.addr_size));
+        shape.tio.recv_peer(&peerindoffset, BITBYTES(depth));
 
         // Reconstruct the total offset
-        auto indshift = combine(indoffset, peerindoffset, shape.addr_size);
+        auto indshift = combine(indoffset, peerindoffset, depth);
 
         // Evaluate the DPFs and compute the dotproducts
         ParallelEval pe(dp, IfRegAS<U>(indshift), IfRegXS<U>(indshift),
@@ -335,16 +336,17 @@ Duoram<T>::Shape::MemRefS<U,FT,FST,Sh,WIDTH>::operator FT()
     } else {
         // The server does this
 
-        RDPFPair<1> dp = shape.tio.rdpfpair(shape.yield, shape.addr_size);
+        const RDPFPair<1> &dp = *(oblividx->dp);
+        const nbits_t depth = dp.depth();
         U p0indoffset, p1indoffset;
 
         shape.yield();
 
         // Receive the index offset from the computational players and
         // combine them
-        shape.tio.recv_p0(&p0indoffset, BITBYTES(shape.addr_size));
-        shape.tio.recv_p1(&p1indoffset, BITBYTES(shape.addr_size));
-        auto indshift = combine(p0indoffset, p1indoffset, shape.addr_size);
+        shape.tio.recv_p0(&p0indoffset, BITBYTES(depth));
+        shape.tio.recv_p1(&p1indoffset, BITBYTES(depth));
+        auto indshift = combine(p0indoffset, p1indoffset, depth);
 
         // Evaluate the DPFs to compute the cancellation terms
         std::tuple<FT,FT> init, gamma;
@@ -394,7 +396,8 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
     if (player < 2) {
         // Computational players do this
 
-        RDPFTriple<1> dt = shape.tio.rdpftriple(shape.yield, shape.addr_size);
+        const RDPFTriple<1> &dt = *(oblividx->dt);
+        const nbits_t depth = dt.depth();
 
         // Compute the index and message offsets
         U indoffset;
@@ -409,9 +412,9 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
 
         // Send them to the peer, and everything except the first offset
         // to the server
-        shape.tio.queue_peer(&indoffset, BITBYTES(shape.addr_size));
+        shape.tio.queue_peer(&indoffset, BITBYTES(depth));
         shape.tio.iostream_peer() << Moffset;
-        shape.tio.queue_server(&indoffset, BITBYTES(shape.addr_size));
+        shape.tio.queue_server(&indoffset, BITBYTES(depth));
         shape.tio.iostream_server() << std::get<1>(Moffset) <<
             std::get<2>(Moffset);
 
@@ -420,11 +423,11 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
         // Receive the above from the peer
         U peerindoffset;
         RDPFTriple<1>::WTriple<FT> peerMoffset;
-        shape.tio.recv_peer(&peerindoffset, BITBYTES(shape.addr_size));
+        shape.tio.recv_peer(&peerindoffset, BITBYTES(depth));
         shape.tio.iostream_peer() >> peerMoffset;
 
         // Reconstruct the total offsets
-        auto indshift = combine(indoffset, peerindoffset, shape.addr_size);
+        auto indshift = combine(indoffset, peerindoffset, depth);
         auto Mshift = combine(Moffset, peerMoffset);
 
         // Evaluate the DPFs and add them to the database
@@ -456,7 +459,8 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
     } else {
         // The server does this
 
-        RDPFPair<1> dp = shape.tio.rdpfpair(shape.yield, shape.addr_size);
+        const RDPFPair<1> &dp = *(oblividx->dp);
+        const nbits_t depth = dp.depth();
         U p0indoffset, p1indoffset;
         RDPFPair<1>::WPair<FT> p0Moffset, p1Moffset;
 
@@ -464,11 +468,11 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
 
         // Receive the index and message offsets from the computational
         // players and combine them
-        shape.tio.recv_p0(&p0indoffset, BITBYTES(shape.addr_size));
+        shape.tio.recv_p0(&p0indoffset, BITBYTES(depth));
         shape.tio.iostream_p0() >> p0Moffset;
-        shape.tio.recv_p1(&p1indoffset, BITBYTES(shape.addr_size));
+        shape.tio.recv_p1(&p1indoffset, BITBYTES(depth));
         shape.tio.iostream_p1() >> p1Moffset;
-        auto indshift = combine(p0indoffset, p1indoffset, shape.addr_size);
+        auto indshift = combine(p0indoffset, p1indoffset, depth);
         auto Mshift = combine(p0Moffset, p1Moffset);
 
         // Evaluate the DPFs and subtract them from the blinds

+ 30 - 3
online.cpp

@@ -260,8 +260,11 @@ static void rdpf_test(MPCIO &mpcio,
                     RDPF<WIDTH> &dpf = dt.dpf[i];
                     for (nbits_t level=min_level; level<=depth; ++level) {
                         if (incremental) {
-                            printf("Level = %u\n\n", level);
-                            dpf.depth(level);
+                            printf("Level = %u\n", level);
+                            dt.depth(level);
+                            RegXS tshare;
+                            dt.get_target(tshare);
+                            printf("Target share = %lx\n\n", tshare.share());
                         }
                         typename RDPF<WIDTH>::RegXSW peer_scaled_xor;
                         typename RDPF<WIDTH>::RegASW peer_scaled_sum;
@@ -1228,8 +1231,10 @@ static void bsearch_test(MPCIO &mpcio,
     }
 
     MPCTIO tio(mpcio, 0, opts.num_threads);
-    run_coroutines(tio, [&tio, depth, len, target, basic] (yield_t &yield) {
+    run_coroutines(tio, [&tio, &mpcio, depth, len, target, basic] (yield_t &yield) {
         RegAS tshare;
+        std::cout << "\n===== SETUP =====\n";
+
         if (tio.player() == 2) {
             // Send shares of the target to the computational
             // players
@@ -1245,6 +1250,12 @@ static void bsearch_test(MPCIO &mpcio,
             tio.iostream_server() >> tshare;
         }
 
+        tio.sync_lamport();
+        mpcio.dump_stats(std::cout);
+
+        std::cout << "\n===== SORT RANDOM DATABASE =====\n";
+        mpcio.reset_stats();
+        tio.reset_lamport();
         // Create a random database and sort it
         // size_t &aes_ops = tio.aes_ops();
         Duoram<RegAS> oram(tio.player(), len);
@@ -1265,6 +1276,12 @@ static void bsearch_test(MPCIO &mpcio,
         A.bitonic_sort(0, len);
         A.explicitonly(false);
 
+        tio.sync_lamport();
+        mpcio.dump_stats(std::cout);
+
+        std::cout << "\n===== BINARY SEARCH =====\n";
+        mpcio.reset_stats();
+        tio.reset_lamport();
         // Binary search for the target
         value_t checkindex;
         if (basic) {
@@ -1275,6 +1292,12 @@ static void bsearch_test(MPCIO &mpcio,
             checkindex = mpc_reconstruct(tio, yield, tindex);
         }
 
+        tio.sync_lamport();
+        mpcio.dump_stats(std::cout);
+
+        std::cout << "\n===== CHECK ANSWER =====\n";
+        mpcio.reset_stats();
+        tio.reset_lamport();
         // Check the answer
         size_t size = size_t(1) << depth;
         value_t checktarget = mpc_reconstruct(tio, yield, tshare);
@@ -1300,6 +1323,10 @@ static void bsearch_test(MPCIO &mpcio,
                     }
                 }
             }
+            if (checkindex == len && check[len-1].share() >= checktarget) {
+                fail = true;
+            }
+
             printf("Target = %016lx\n", checktarget);
             printf("Found index = %02lx\n", checkindex);
             if (checkindex > size) {

+ 4 - 1
rdpf.hpp

@@ -289,8 +289,11 @@ struct RDPFTriple {
     // outputs so that the appropriate one can be selected with a
     // parameter
 
+    // Only RegXS, not RegAS, indices are used with incremental RDPFs
     inline void get_target(RegAS &target) const { target = as_target; }
-    inline void get_target(RegXS &target) const { target = xs_target; }
+    inline void get_target(RegXS &target) const {
+        target = xs_target >> (dpf[0].maxdepth - dpf[0].curdepth);
+    }
 
     // Additive share of the scaling value M_as such that the high words
     // of the leaf values for P0 and P1 add to M_as * e_{target}