Ian Goldberg 1 рік тому
батько
коміт
61327a757f
4 змінених файлів з 135 додано та 10 видалено
  1. 5 0
      duoram.hpp
  2. 104 2
      duoram.tcc
  3. 15 8
      online.cpp
  4. 11 0
      rdpf.hpp

+ 5 - 0
duoram.hpp

@@ -172,7 +172,12 @@ public:
 
     // For debugging or checking your answers (using this in general is
     // of course insecure)
+
+    // This one reconstructs the whole database
     std::vector<T> reconstruct() const;
+
+    // This one reconstructs a single database value
+    T reconstruct(const T& share) const;
 };
 
 // The most basic shape is Flat.  It is almost always the topmost shape,

+ 104 - 2
duoram.tcc

@@ -35,6 +35,7 @@ void Duoram<T>::dump() const
 
 // For debugging or checking your answers (using this in general is
 // of course insecure)
+// This one reconstructs the whole database
 template <typename T>
 std::vector<T> Duoram<T>::Shape::reconstruct() const
 {
@@ -56,6 +57,26 @@ std::vector<T> Duoram<T>::Shape::reconstruct() const
     return res;
 }
 
+// This one reconstructs a single database value
+template <typename T>
+T Duoram<T>::Shape::reconstruct(const T& share) const
+{
+    int player = tio.player();
+    T res;
+
+    // Player 1 sends their share of the value to player 0
+    if (player == 1) {
+        tio.queue_peer(&share, sizeof(T));
+    } else if (player == 0) {
+        tio.recv_peer(&res, sizeof(T));
+        res += share;
+    }
+    // The server (player 2) does nothing
+
+    // Players 1 and 2 will get 0 here
+    return res;
+}
+
 // Function to set the shape_size of a shape and compute the number of
 // bits you need to address a shape of that size (which is the number of
 // bits in sz-1).  This is typically called by subclass constructors.
@@ -98,7 +119,88 @@ template <typename T>
 Duoram<T>::Shape::MemRefAS::operator T()
 {
     T res;
-    return res;
+    int player = shape.tio.player();
+    if (player < 2) {
+        // Computational players do this
+
+        RDPFTriple dt = shape.tio.rdpftriple(shape.addr_size);
+
+        // Compute the index offset
+        RegAS indoffset = idx;
+        indoffset -= dt.as_target;
+
+        // We only need two of the DPFs for reading
+        RDPFPair dp(std::move(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.yield();
+
+        // Receive the above from the peer
+        RegAS peerindoffset;
+        shape.tio.recv_peer(&peerindoffset, BITBYTES(shape.addr_size));
+
+        // Reconstruct the total offset
+        auto indshift = combine(indoffset, peerindoffset, shape.addr_size);
+
+        // Evaluate the DPFs and compute the dotproducts
+        StreamEval ev(dp, -indshift, shape.tio.aes_ops());
+        for (size_t i=0; i<shape.shape_size; ++i) {
+            auto L = ev.next();
+            // The values from the two DPFs
+            auto [V0, V1] = dp.unit_as(L);
+            // References to the appropriate cells in our database, our
+            // blind, and our copy of the peer's blinded database
+            auto [DB, BL, PBD] = shape.get_comp(i);
+            res += (DB + PBD) * V0.share() - BL * (V1-V0).share();
+        }
+
+        // Receive the cancellation term from the server
+        T gamma;
+        shape.tio.iostream_server() >> gamma;
+        res += gamma;
+    } else {
+        // The server does this
+
+        RDPFPair dp = shape.tio.rdpfpair(shape.addr_size);
+        RegAS p0indoffset, p1indoffset;
+
+        // 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);
+
+        // Evaluate the DPFs to compute the cancellation terms
+        T gamma0, gamma1;
+        StreamEval ev(dp, -indshift, shape.tio.aes_ops());
+        for (size_t i=0; i<shape.shape_size; ++i) {
+            auto L = ev.next();
+
+            // The values from the two DPFs
+            auto [V0, V1] = dp.unit_as(L);
+
+            // shape.get_server(i) returns a pair of references to the
+            // appropriate cells in the two blinded databases
+            auto [BL0, BL1] = shape.get_server(i);
+            gamma0 -= BL0 * V1.share();
+            gamma1 -= BL1 * V0.share();
+        }
+
+        // Choose a random blinding factor
+        T rho;
+        rho.randomize();
+
+        gamma0 += rho;
+        gamma1 -= rho;
+
+        // Send the cancellation terms to the computational players
+        shape.tio.iostream_p0() << gamma0;
+        shape.tio.iostream_p1() << gamma1;
+    }
+    return res;  // The server will always get 0
 }
 
 // Oblivious update to an additively shared index of Duoram memory
@@ -169,7 +271,7 @@ typename Duoram<T>::Shape::MemRefAS
         shape.tio.iostream_p0() >> p0Moffset;
         shape.tio.recv_p1(&p1indoffset, BITBYTES(shape.addr_size));
         shape.tio.iostream_p1() >> p1Moffset;
-        auto indshift = combine(p0indoffset, p1indoffset);
+        auto indshift = combine(p0indoffset, p1indoffset, shape.addr_size);
         auto Mshift = combine(p0Moffset, p1Moffset);
 
         // Evaluate the DPFs and subtract them from the blinds

+ 15 - 8
online.cpp

@@ -448,20 +448,27 @@ static void duoram_test(MPCIO &mpcio, yield_t &yield,
                 M.ashare = 0x0000a66e;
             }
             RegXS xidx;
-            xidx.randomize(depth);
-            size_t eidx = arc4random();
-            eidx &= (size-1);
+            xidx.xshare = share;
+            size_t eidx = share;
+            printf("Updating\n");
             A[aidx] += M;
+            printf("Reading\n");
             RegAS Aa = A[aidx];
             auto Ax = A[xidx];
             auto Ae = A[eidx];
-            oram.dump();
-            auto check = A.reconstruct();
-            if (tio.player() == 0) {
-                for (address_t i=0;i<size;++i) {
-                    printf("%04x %016lx\n", i, check[i].ashare);
+            if (depth <= 10) {
+                oram.dump();
+                auto check = A.reconstruct();
+                if (tio.player() == 0) {
+                    for (address_t i=0;i<size;++i) {
+                        printf("%04x %016lx\n", i, check[i].ashare);
+                    }
                 }
             }
+            auto checkread = A.reconstruct(Aa);
+            if (tio.player() == 0) {
+                printf("Read value = %016lx\n", checkread.share());
+            }
             tio.send();
         });
     }

+ 11 - 0
rdpf.hpp

@@ -254,6 +254,17 @@ struct RDPFPair {
 
     RDPF dpf[2];
 
+    RDPFPair() {}
+
+    // Create an RDPFPair from an RDPFTriple, keeping two of the RDPFs
+    // and dropping one.  This _moves_ the dpfs from the triple to the
+    // pair, so the triple will no longer be valid after using this.
+    // which0 and which1 indicate which of the dpfs to keep.
+    RDPFPair(RDPFTriple &&trip, int which0, int which1) {
+        dpf[0] = std::move(trip.dpf[which0]);
+        dpf[1] = std::move(trip.dpf[which1]);
+    }
+
     // The depth
     inline nbits_t depth() const { return dpf[0].depth(); }