Ver código fonte

Start on the update protocol

Ian Goldberg 2 anos atrás
pai
commit
3ec5dd0de4
4 arquivos alterados com 115 adições e 47 exclusões
  1. 31 17
      duoram.hpp
  2. 77 2
      duoram.tcc
  3. 7 0
      online.cpp
  4. 0 28
      rdpf.hpp

+ 31 - 17
duoram.hpp

@@ -57,19 +57,6 @@ public:
     // These are the different Shapes that exist
     class Flat;
 
-    // When you index into a shape (A[x]), you get one of these types,
-    // depending on the type of x (the index), _not_ on the type T (the
-    // underlying type of the Duoram).  That is, you can have an
-    // additive-shared index (x) into an XOR-shared database (T), for
-    // example.
-
-    // When x is unshared explicit value
-    class MemRefExpl;
-    // When x is additively shared
-    class MemRefAS;
-    // When x is XOR shared
-    class MemRefXS;
-
     // Pass the player number and desired size
     Duoram(int player, size_t size);
 
@@ -91,6 +78,19 @@ class Duoram<T>::Shape {
     // Subclasses should be able to access _other_ Shapes' indexmap
     friend class Flat;
 
+    // When you index into a shape (A[x]), you get one of these types,
+    // depending on the type of x (the index), _not_ on the type T (the
+    // underlying type of the Duoram).  That is, you can have an
+    // additive-shared index (x) into an XOR-shared database (T), for
+    // example.
+
+    // When x is unshared explicit value
+    class MemRefExpl;
+    // When x is additively shared
+    class MemRefAS;
+    // When x is XOR shared
+    class MemRefXS;
+
 protected:
     // A reference to the parent shape.  As with ".." in the root
     // directory of a filesystem, the topmost shape is indicated by
@@ -103,10 +103,21 @@ protected:
     // The size of this shape
     size_t shape_size;
 
+    // The number of bits needed to address this shape (the number of
+    // bits in shape_size-1)
+    nbits_t addr_size;
+
+    // And a mask with the low addr_size bits set
+    address_t addr_mask;
+
     // The Shape's context (MPCTIO and yield_t)
     MPCTIO &tio;
     yield_t &yield;
 
+    // A function to set the shape_size and compute addr_size and
+    // addr_mask
+    void set_shape_size(size_t sz);
+
     // We need a constructor because we hold non-static references; this
     // constructor is called by the subclass constructors
     Shape(const Shape &parent, Duoram &duoram, MPCTIO &tio,
@@ -170,7 +181,7 @@ public:
 // perform operations on this object, which do the Duoram operations.
 
 template <typename T>
-class Duoram<T>::MemRefAS {
+class Duoram<T>::Shape::MemRefAS {
     const Shape &shape;
     RegAS idx;
 
@@ -178,8 +189,11 @@ public:
     MemRefAS(const Shape &shape, const RegAS &idx) :
         shape(shape), idx(idx) {}
 
-    // Oblivious read from an additively shared index into Duoram memory
+    // Oblivious read from an additively shared index of Duoram memory
     operator T();
+
+    // Oblivious update to an additively shared index of Duoram memory
+    MemRefAS &operator+=(const T& M);
 };
 
 // An XOR shared memory reference.  You get one of these from a Shape A
@@ -187,7 +201,7 @@ public:
 // operations on this object, which do the Duoram operations.
 
 template <typename T>
-class Duoram<T>::MemRefXS {
+class Duoram<T>::Shape::MemRefXS {
     const Shape &shape;
     RegXS idx;
 
@@ -202,7 +216,7 @@ public:
 // operations.
 
 template <typename T>
-class Duoram<T>::MemRefExpl {
+class Duoram<T>::Shape::MemRefExpl {
     const Shape &shape;
     address_t idx;
 

+ 77 - 2
duoram.tcc

@@ -37,6 +37,25 @@ std::vector<T> Duoram<T>::Shape::reconstruct() const
     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.
+template <typename T>
+void Duoram<T>::Shape::set_shape_size(size_t sz)
+{
+    shape_size = sz;
+    // Compute the number of bits in (sz-1)
+    // But use 0 if sz=0 for some reason (though that should never
+    // happen)
+    if (sz > 1) {
+        addr_size = 64-__builtin_clzll(sz-1);
+        addr_mask = address_t((size_t(1)<<addr_size)-1);
+    } else {
+        addr_size = 0;
+        addr_mask = 0;
+    }
+}
+
 // Constructor for the Flat shape.  len=0 means the maximum size (the
 // parent's size minus start).
 template <typename T>
@@ -52,12 +71,68 @@ Duoram<T>::Flat::Flat(Duoram &duoram, MPCTIO &tio, yield_t &yield,
     if (len > maxshapesize || len == 0) {
         len = maxshapesize;
     }
-    this->shape_size = len;
+    this->set_shape_size(len);
 }
 
+// Oblivious read from an additively shared index of Duoram memory
 template <typename T>
-Duoram<T>::MemRefAS::operator T()
+Duoram<T>::Shape::MemRefAS::operator T()
 {
     T res;
     return res;
 }
+
+// Oblivious update to an additively shared index of Duoram memory
+template <typename T>
+typename Duoram<T>::Shape::MemRefAS
+    &Duoram<T>::Shape::MemRefAS::operator+=(const T& M)
+{
+    int player = shape.tio.player();
+    if (player < 2) {
+        // Computational players do this
+        RDPFTriple dt = shape.tio.rdpftriple(shape.addr_size);
+        RegAS indoffset = idx;
+        indoffset -= dt.as_target;
+        RegAS Moffset[3];
+        Moffset[0] = Moffset[1] = Moffset[2] = M;
+        Moffset[0] -= dt.dpf[0].scaled_sum;
+        Moffset[1] -= dt.dpf[1].scaled_sum;
+        Moffset[2] -= dt.dpf[2].scaled_sum;
+        shape.tio.queue_peer(&indoffset, BITBYTES(shape.addr_size));
+        shape.tio.iostream_peer() << Moffset[0] << Moffset[1] <<
+            Moffset[2];
+        shape.tio.queue_server(&indoffset, BITBYTES(shape.addr_size));
+        shape.tio.iostream_server() << Moffset[1] << Moffset[2];
+        shape.yield();
+        RegAS peerindoffset;
+        RegAS peerMoffset[3];
+        shape.tio.recv_peer(&peerindoffset, BITBYTES(shape.addr_size));
+        shape.tio.iostream_peer() >> peerMoffset[0] >> peerMoffset[1] >>
+            peerMoffset[2];
+        indoffset += peerindoffset;
+        indoffset &= shape.addr_mask;
+        Moffset[0] += peerMoffset[0];
+        Moffset[1] += peerMoffset[1];
+        Moffset[2] += peerMoffset[2];
+        StreamEval<RDPFTriple> ev(dt, indoffset.ashare,
+            shape.tio.aes_ops());
+        for (size_t i=0; i<shape.shape_size; ++i) {
+            auto [L0, L1, L2] = ev.next();
+
+        }
+    } else {
+        // The server does this
+        RDPFPair dp = shape.tio.rdpfpair(shape.addr_size);
+        RegAS p0indoffset, p1indoffset;
+        RegAS p0Moffset[2];
+        RegAS p1Moffset[2];
+        shape.tio.recv_p0(&p0indoffset, BITBYTES(shape.addr_size));
+        shape.tio.iostream_p0() >> p0Moffset[0] >> p0Moffset[1];
+        shape.tio.recv_p1(&p1indoffset, BITBYTES(shape.addr_size));
+        shape.tio.iostream_p1() >> p1Moffset[0] >> p1Moffset[1];
+        p0indoffset += p1indoffset;
+        p0Moffset[0] += p1Moffset[0];
+        p0Moffset[1] += p1Moffset[1];
+    }
+    return *this;
+}

+ 7 - 0
online.cpp

@@ -436,10 +436,17 @@ static void duoram_test(MPCIO &mpcio, yield_t &yield,
             auto A = oram.flat(tio, yield);
             RegAS aidx;
             aidx.randomize(depth);
+            RegAS M;
+            if (tio.player() == 0) {
+                M.ashare = 0xbabb0000;
+            } else {
+                M.ashare = 0x0000a66e;
+            }
             RegXS xidx;
             xidx.randomize(depth);
             size_t eidx = arc4random();
             eidx &= (size-1);
+            A[aidx] += M;
             RegAS Aa = A[aidx];
             auto Ax = A[xidx];
             auto Ae = A[eidx];

+ 0 - 28
rdpf.hpp

@@ -112,34 +112,6 @@ struct RDPF {
     // Expand the DPF if it's not already expanded
     void expand(size_t &op_counter);
 
-#if 0
-    // Streaming evaluation, to avoid taking up enough memory to store
-    // an entire evaluation
-    class Eval {
-        friend class RDPF; // So eval() can call the Eval constructor
-        const RDPF &rdpf;
-        size_t &op_counter;
-        bool use_expansion;
-        nbits_t depth;
-        address_t indexmask;
-        address_t pathindex;
-        address_t nextindex;
-        std::vector<DPFnode> path;
-        Eval(const RDPF &rdpf, size_t &op_counter, address_t start,
-            bool use_expansion);
-    public:
-        DPFnode next();
-    };
-
-    // Create an Eval object that will start its output at index start.
-    // It will wrap around to 0 when it hits 2^depth.  If use_expansion
-    // is true, then if the DPF has been expanded, just output values
-    // from that.  If use_expansion=false or if the DPF has not been
-    // expanded, compute the values on the fly.
-    StreamEval<RDPF> eval(address_t start, size_t &op_counter,
-        bool use_expansion=true) const;
-#endif
-
     // Get the bit-shared unit vector entry from the leaf node
     inline RegBS unit_bs(DPFnode leaf) const {
         RegBS b;