Browse Source

Writes (= reads + updates)

For additive shared, XOR shared and explicit indices, and multiple
independent lists of those.
Ian Goldberg 2 years ago
parent
commit
2b29022d8c
4 changed files with 139 additions and 13 deletions
  1. 20 6
      duoram.hpp
  2. 65 1
      duoram.tcc
  3. 9 5
      online.cpp
  4. 45 1
      types.hpp

+ 20 - 6
duoram.hpp

@@ -307,12 +307,15 @@ protected:
 
 public:
 
-    // Oblivious read from an additively shared index of Duoram memory
+    // Oblivious read from a shared index of Duoram memory
     virtual operator T() = 0;
 
-    // Oblivious update to an additively shared index of Duoram memory
+    // Oblivious update to a shared index of Duoram memory
     virtual MemRef &operator+=(const T& M) = 0;
 
+    // Oblivious write to a shared index of Duoram memory
+    virtual MemRef &operator=(const T& M) = 0;
+
     // Convenience function
     MemRef &operator-=(const T& M) { *this += (-M); return *this; }
 
@@ -333,11 +336,14 @@ public:
     MemRefS<U>(Shape &shape, const U &idx) :
         MemRef(shape), idx(idx) {}
 
-    // Oblivious read from an additively shared index of Duoram memory
+    // Oblivious read from a shared index of Duoram memory
     operator T() override;
 
-    // Oblivious update to an additively shared index of Duoram memory
+    // Oblivious update to a shared index of Duoram memory
     MemRefS<U> &operator+=(const T& M) override;
+
+    // Oblivious write to a shared index of Duoram memory
+    MemRefS<U> &operator=(const T& M) override;
 };
 
 // An explicit memory reference.  You get one of these from a Shape A
@@ -359,6 +365,9 @@ public:
     // Explicit update to a given index of Duoram memory
     MemRefExpl &operator+=(const T& M) override;
 
+    // Explicit write to a given index of Duoram memory
+    MemRefExpl &operator=(const T& M) override;
+
     // Convenience function
     MemRefExpl &operator-=(const T& M) { *this += (-M); return *this; }
 };
@@ -380,14 +389,19 @@ public:
     MemRefInd(Sh &shape, std::array<U,N> aindcs) :
         shape(shape) { for ( auto &i : aindcs ) { indcs.push_back(i); } }
 
-    // Explicit read from a given index of Duoram memory
+    // Independent reads from shared or explicit indices of Duoram memory
     operator std::vector<T>();
 
-    // Explicit update to a given index of Duoram memory
+    // Independent updates to shared or explicit indices of Duoram memory
     MemRefInd &operator+=(const std::vector<T>& M);
     template <size_t N>
     MemRefInd &operator+=(const std::array<T,N>& M);
 
+    // Independent writes to shared or explicit indices of Duoram memory
+    MemRefInd &operator=(const std::vector<T>& M);
+    template <size_t N>
+    MemRefInd &operator=(const std::array<T,N>& M);
+
     // Convenience function
     MemRefInd &operator-=(const std::vector<T>& M) { *this += (-M); return *this; }
     template <size_t N>

+ 65 - 1
duoram.tcc

@@ -392,7 +392,7 @@ Duoram<T>::Shape::MemRefS<U>::operator T()
     return res;  // The server will always get 0
 }
 
-// Oblivious update to an additively shared index of Duoram memory
+// Oblivious update to an additively or XOR shared index of Duoram memory
 template <typename T> template <typename U>
 typename Duoram<T>::Shape::template MemRefS<U>
     &Duoram<T>::Shape::MemRefS<U>::operator+=(const T& M)
@@ -488,6 +488,17 @@ typename Duoram<T>::Shape::template MemRefS<U>
     return *this;
 }
 
+// Oblivious write to an additively or XOR shared index of Duoram memory
+template <typename T> template <typename U>
+typename Duoram<T>::Shape::template MemRefS<U>
+    &Duoram<T>::Shape::MemRefS<U>::operator=(const T& M)
+{
+    T oldval = *this;
+    T update = M - oldval;
+    *this += update;
+    return *this;
+}
+
 // Oblivious sort with the provided other element.  Without
 // reconstructing the values, *this will become a share of the
 // smaller of the reconstructed values, and other will become a
@@ -597,6 +608,17 @@ typename Duoram<T>::Shape::MemRefExpl
     return *this;
 }
 
+// Explicit write to a given index of Duoram memory
+template <typename T>
+typename Duoram<T>::Shape::MemRefExpl
+    &Duoram<T>::Shape::MemRefExpl::operator=(const T& M)
+{
+    T oldval = *this;
+    T update = M - oldval;
+    *this += update;
+    return *this;
+}
+
 // Independent U-shared reads into a Shape of subtype Sh on a Duoram
 // with values of sharing type T
 template <typename T> template <typename U, typename Sh>
@@ -658,3 +680,45 @@ typename Duoram<T>::Shape::template MemRefInd<U,Sh>
 
     return *this;
 }
+
+// Independent U-shared writes into a Shape of subtype Sh on a Duoram
+// with values of sharing type T (vector version)
+template <typename T> template <typename U, typename Sh>
+typename Duoram<T>::Shape::template MemRefInd<U,Sh>
+    &Duoram<T>::Shape::MemRefInd<U,Sh>::operator=(const std::vector<T>& M)
+{
+    size_t size = indcs.size();
+    assert(M.size() == size);
+
+    std::vector<coro_t> coroutines;
+    for (size_t i=0;i<size;++i) {
+        coroutines.emplace_back([this, &M, i] (yield_t &yield) {
+            Sh Sh_coro = shape.context(yield);
+            Sh_coro[indcs[i]] = M[i];
+        });
+    }
+    run_coroutines(shape.yield, coroutines);
+
+    return *this;
+}
+
+// Independent U-shared writes into a Shape of subtype Sh on a Duoram
+// with values of sharing type T (array version)
+template <typename T> template <typename U, typename Sh> template <size_t N>
+typename Duoram<T>::Shape::template MemRefInd<U,Sh>
+    &Duoram<T>::Shape::MemRefInd<U,Sh>::operator=(const std::array<T,N>& M)
+{
+    size_t size = indcs.size();
+    assert(N == size);
+
+    std::vector<coro_t> coroutines;
+    for (size_t i=0;i<size;++i) {
+        coroutines.emplace_back([this, &M, i] (yield_t &yield) {
+            Sh Sh_coro = shape.context(yield);
+            Sh_coro[indcs[i]] = M[i];
+        });
+    }
+    run_coroutines(shape.yield, coroutines);
+
+    return *this;
+}

+ 9 - 5
online.cpp

@@ -595,23 +595,26 @@ static void duoram_test(MPCIO &mpcio,
             N.set(0x0000beef);
         }
         // Writing and reading with additively shared indices
-        printf("Updating\n");
+        printf("Additive Updating\n");
         A[aidx] += M;
-        printf("Reading\n");
+        printf("Additive Reading\n");
         T Aa = A[aidx];
         // Writing and reading with XOR shared indices
-        printf("Updating\n");
+        printf("XOR Updating\n");
         A[xidx] += N;
-        printf("Reading\n");
+        printf("XOR Reading\n");
         T Ax = A[xidx];
         T Ae;
         // Writing and reading with explicit indices
         if (depth > 2) {
+            printf("Explicit Updating\n");
             A[5] += Aa;
+            printf("Explicit Reading\n");
             Ae = A[6];
         }
 
         // Simultaneous independent reads
+        printf("3 independent reading\n");
         std::vector<T> Av = A.indep(std::array {
             aidx, aidx2, aidx3
         });
@@ -621,7 +624,8 @@ static void duoram_test(MPCIO &mpcio,
         Aw1.set(0x101010101010101 * tio.player());
         Aw2.set(0x202020202020202 * tio.player());
         Aw3.set(0x303030303030303 * tio.player());
-        A.indep(std::array { aidx, aidx2, aidx3 }) +=
+        printf("3 independent updating\n");
+        A.indep(std::array { aidx, aidx2, aidx3 }) -=
             std::array { Aw1, Aw2, Aw3 };
 
         if (depth <= 10) {

+ 45 - 1
types.hpp

@@ -2,6 +2,8 @@
 #define __OBLIVDS_TYPES_HPP__
 
 #include <tuple>
+#include <vector>
+#include <array>
 #include <cstdint>
 #include <x86intrin.h>  // SSE and AVX intrinsics
 #include <bsd/stdlib.h> // arc4random_buf
@@ -256,7 +258,8 @@ inline value_t combine(const RegXS &A, const RegXS &B,
     return (A.xshare ^ B.xshare) & mask;
 }
 
-// Some useful operations on tuples of the above types
+// Some useful operations on tuples, vectors, and arrays of the above
+// types
 
 template <typename T>
 std::tuple<T,T> operator+=(std::tuple<T,T> &A,
@@ -435,6 +438,47 @@ std::tuple<T,T,T> operator*(const std::tuple<T,T,T> &A,
     return res;
 }
 
+inline std::vector<RegAS> operator-(const std::vector<RegAS> &A)
+{
+    std::vector<RegAS> res;
+    for (const auto &v : A) {
+        res.push_back(-v);
+    }
+    return res;
+}
+
+inline std::vector<RegXS> operator-(const std::vector<RegXS> &A)
+{
+    return A;
+}
+
+inline std::vector<RegBS> operator-(const std::vector<RegBS> &A)
+{
+    return A;
+}
+
+template <size_t N>
+inline std::vector<RegAS> operator-(const std::array<RegAS,N> &A)
+{
+    std::vector<RegAS> res;
+    for (const auto &v : A) {
+        res.push_back(-v);
+    }
+    return res;
+}
+
+template <size_t N>
+inline std::array<RegXS,N> operator-(const std::array<RegXS,N> &A)
+{
+    return A;
+}
+
+template <size_t N>
+inline std::array<RegBS,N> operator-(const std::array<RegBS,N> &A)
+{
+    return A;
+}
+
 template <typename T>
 inline std::tuple<value_t,value_t,value_t> combine(
         const std::tuple<T,T,T> &A, const std::tuple<T,T,T> &B,