Browse Source

Start on OblivIndex related-index ORAM accesses

Ian Goldberg 1 year ago
parent
commit
95ee232971
2 changed files with 74 additions and 10 deletions
  1. 71 7
      duoram.hpp
  2. 3 3
      duoram.tcc

+ 71 - 7
duoram.hpp

@@ -1,6 +1,8 @@
 #ifndef __DUORAM_HPP__
 #define __DUORAM_HPP__
 
+#include <optional>
+
 #include "types.hpp"
 #include "mpcio.hpp"
 #include "coroutine.hpp"
@@ -22,10 +24,8 @@
 // on a Shape shared with other threads or coroutines.
 
 // This is templated, because you can have a Duoram of additively shared
-// (RegAS) or XOR shared (RegXS) elements, or std::arrays of those to
-// get "wide" memory cells.
-
-// The initial implementation is focused on additive shares.
+// (RegAS) or XOR shared (RegXS) elements, or more complex cell types
+// (see cell.hpp for example).
 
 template <typename T>
 class Duoram {
@@ -61,6 +61,10 @@ public:
     class Pad;
     class Stride;
 
+    // Oblivious indices for use in related-index ORAM accesses
+    template <typename U, nbits_t WIDTH>
+    class OblivIndex;
+
     // Pass the player number and desired size
     Duoram(int player, size_t size);
 
@@ -88,6 +92,9 @@ class Duoram<T>::Shape {
     friend class Pad;
     friend class Stride;
 
+    template <typename U, nbits_t WIDTH>
+    friend class OblivIndex;
+
     // 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
@@ -361,6 +368,49 @@ public:
     RegAS obliv_binary_search(RegAS &target);
 };
 
+// Oblivious indices for use in related-index ORAM accesses.
+
+template <typename T>
+template <typename U, nbits_t WIDTH>
+class Duoram<T>::OblivIndex {
+    template <typename Ux,typename FT,typename FST,typename Sh,nbits_t WIDTHx>
+    friend class Shape::MemRefS;
+
+    int player;
+    std::optional<RDPFTriple<WIDTH>> dt;
+    std::optional<RDPFPair<WIDTH>> dp;
+    nbits_t curdepth, maxdepth;
+    nbits_t next_windex;
+    bool incremental;
+    U idx;
+
+public:
+    // Non-incremental constructor
+    OblivIndex(MPCTIO &tio, yield_t &yield, const U &idx, nbits_t depth) :
+        player(tio.player()), curdepth(depth), maxdepth(depth),
+        next_windex(0), incremental(false), idx(idx)
+    {
+        if (player < 2) {
+            dt = tio.rdpftriple(yield, depth);
+        } else {
+            dp = tio.rdpfpair(yield, depth);
+        }
+    }
+
+    // Incremental constructor: only for U=RegXS
+    OblivIndex(MPCTIO &tio, yield_t &yield, nbits_t depth) :
+        player(tio.player()), curdepth(0), maxdepth(depth),
+        next_windex(0), incremental(true), idx(RegXS())
+    {
+        if (player < 2) {
+            dt = tio.rdpftriple(yield, depth, true);
+        } else {
+            dp = tio.rdpfpair(yield, depth, true);
+        }
+    }
+
+};
+
 // An additive or XOR shared memory reference.  You get one of these
 // from a Shape A and an additively shared RegAS index x, or an XOR
 // shared RegXS index x, with A[x].  Then you perform operations on this
@@ -378,7 +428,16 @@ template <typename T>
 template <typename U, typename FT, typename FST, typename Sh, nbits_t WIDTH>
 class Duoram<T>::Shape::MemRefS {
     Sh &shape;
-    U idx;
+    // oblividx is a reference to the OblivIndex we're using.  In the
+    // common case, we own the actual OblivIndex, and it's stored in
+    // our_oblividx, and oblividx is a pointer to that.  Sometimes
+    // (for example incremental ORAM accesses), the caller will own (and
+    // modify between uses) the OblivIndex.  In that case, oblividx will
+    // be a pointer to the caller's OblivIndex object, and
+    // our_oblividx will be nullopt.
+    std::optional<Duoram<T>::OblivIndex<U,WIDTH>> our_oblividx;
+    Duoram<T>::OblivIndex<U,WIDTH> *oblividx;
+
     FST fieldsel;
 
 private:
@@ -391,12 +450,17 @@ private:
 
 public:
     MemRefS<U,FT,FST,Sh,WIDTH>(Sh &shape, const U &idx, FST fieldsel) :
-        shape(shape), idx(idx), fieldsel(fieldsel) {}
+        shape(shape), fieldsel(fieldsel) {
+        our_oblividx.emplace(shape.tio, shape.yield, idx,
+            shape.addr_size);
+        oblividx = &(*our_oblividx);
+    }
 
     // Create a MemRefExpl for accessing a partcular field of T
     template <typename SFT>
     MemRefS<U,SFT,SFT T::*,Sh,WIDTH> field(SFT T::*subfieldsel) {
-        auto res = MemRefS<U,SFT,SFT T::*,Sh,WIDTH>(this->shape, idx, subfieldsel);
+        auto res = MemRefS<U,SFT,SFT T::*,Sh,WIDTH>(this->shape,
+            oblividx->idx, subfieldsel);
         return res;
     }
 

+ 3 - 3
duoram.tcc

@@ -291,7 +291,7 @@ Duoram<T>::Shape::MemRefS<U,FT,FST,Sh,WIDTH>::operator FT()
         // Compute the index offset
         U indoffset;
         dt.get_target(indoffset);
-        indoffset -= idx;
+        indoffset -= oblividx->idx;
 
         // We only need two of the DPFs for reading
         RDPFPair<1> dp(std::move(dt), 0, player == 0 ? 2 : 1);
@@ -401,7 +401,7 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
         // Compute the index and message offsets
         U indoffset;
         dt.get_target(indoffset);
-        indoffset -= idx;
+        indoffset -= oblividx->idx;
         RDPF<1>::W<FT> MW;
         MW[0] = M;
         auto Moffset = std::make_tuple(MW, MW, MW);
@@ -506,7 +506,7 @@ typename Duoram<T>::Shape::template MemRefS<U,FT,FST,Sh,WIDTH>
     &Duoram<T>::Shape::MemRefS<U,FT,FST,Sh,WIDTH>::oram_update(const FT& M,
         const prac_template_false &)
 {
-    T::update(shape, shape.yield, idx, M);
+    T::update(shape, shape.yield, oblividx->idx, M);
     return *this;
 }