Browse Source

Touch up a few templates and add +, -, * operators to the RegXS class, and XOR-shared databases "just work"!

Ian Goldberg 2 years ago
parent
commit
959a605f44
7 changed files with 184 additions and 92 deletions
  1. 7 7
      duoram.tcc
  2. 13 7
      online.cpp
  3. 2 1
      options.hpp
  4. 4 0
      prac.cpp
  5. 18 77
      rdpf.hpp
  6. 98 0
      rdpf.tcc
  7. 42 0
      types.hpp

+ 7 - 7
duoram.tcc

@@ -150,7 +150,7 @@ Duoram<T>::Shape::MemRefAS::operator T()
         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);
+            auto [V0, V1] = dp.unit<T>(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);
@@ -180,7 +180,7 @@ Duoram<T>::Shape::MemRefAS::operator T()
             auto L = ev.next();
 
             // The values from the two DPFs
-            auto [V0, V1] = dp.unit_as(L);
+            auto [V0, V1] = dp.unit<T>(L);
 
             // shape.get_server(i) returns a pair of references to the
             // appropriate cells in the two blinded databases
@@ -218,7 +218,7 @@ typename Duoram<T>::Shape::MemRefAS
         RegAS indoffset = idx;
         indoffset -= dt.as_target;
         auto Moffset = std::make_tuple(M, M, M);
-        Moffset -= dt.scaled_sum();
+        Moffset -= dt.scaled_value<T>();
 
         // Send them to the peer, and everything except the first offset
         // to the server
@@ -232,7 +232,7 @@ typename Duoram<T>::Shape::MemRefAS
 
         // Receive the above from the peer
         RegAS peerindoffset;
-        std::tuple<RegAS,RegAS,RegAS> peerMoffset;
+        std::tuple<T,T,T> peerMoffset;
         shape.tio.recv_peer(&peerindoffset, BITBYTES(shape.addr_size));
         shape.tio.iostream_peer() >> peerMoffset;
 
@@ -245,7 +245,7 @@ typename Duoram<T>::Shape::MemRefAS
         for (size_t i=0; i<shape.shape_size; ++i) {
             auto L = ev.next();
             // The values from the three DPFs
-            auto [V0, V1, V2] = dt.scaled_as(L) + dt.unit_as(L) * Mshift;
+            auto [V0, V1, V2] = dt.scaled<T>(L) + dt.unit<T>(L) * Mshift;
             // 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);
@@ -263,7 +263,7 @@ typename Duoram<T>::Shape::MemRefAS
 
         RDPFPair dp = shape.tio.rdpfpair(shape.addr_size);
         RegAS p0indoffset, p1indoffset;
-        std::tuple<RegAS,RegAS> p0Moffset, p1Moffset;
+        std::tuple<T,T> p0Moffset, p1Moffset;
 
         // Receive the index and message offsets from the computational
         // players and combine them
@@ -279,7 +279,7 @@ typename Duoram<T>::Shape::MemRefAS
         for (size_t i=0; i<shape.shape_size; ++i) {
             auto L = ev.next();
             // The values from the two DPFs
-            auto V = dp.scaled_as(L) + dp.unit_as(L) * Mshift;
+            auto V = dp.scaled<T>(L) + dp.unit<T>(L) * Mshift;
             // shape.get_server(i) returns a pair of references to the
             // appropriate cells in the two blinded databases, so we can
             // subtract the pair directly.

+ 13 - 7
online.cpp

@@ -414,6 +414,8 @@ static void tupleeval_timing(MPCIO &mpcio, yield_t &yield,
     pool.join();
 }
 
+// T is RegAS or RegXS for additive or XOR shared database respectively
+template <typename T>
 static void duoram_test(MPCIO &mpcio, yield_t &yield,
     const PRACOptions &opts, char **args)
 {
@@ -437,15 +439,15 @@ static void duoram_test(MPCIO &mpcio, yield_t &yield,
             size_t size = size_t(1)<<depth;
             MPCTIO tio(mpcio, thread_num);
             // size_t &op_counter = tio.aes_ops();
-            Duoram<RegAS> oram(mpcio.player, size);
+            Duoram<T> oram(mpcio.player, size);
             auto A = oram.flat(tio, yield);
             RegAS aidx;
             aidx.ashare = share;
-            RegAS M;
+            T M;
             if (tio.player() == 0) {
-                M.ashare = 0xbabb0000;
+                M.set(0xbabb0000);
             } else {
-                M.ashare = 0x0000a66e;
+                M.set(0x0000a66e);
             }
             RegXS xidx;
             xidx.xshare = share;
@@ -453,7 +455,7 @@ static void duoram_test(MPCIO &mpcio, yield_t &yield,
             printf("Updating\n");
             A[aidx] += M;
             printf("Reading\n");
-            RegAS Aa = A[aidx];
+            T Aa = A[aidx];
             auto Ax = A[xidx];
             auto Ae = A[eidx];
             if (depth <= 10) {
@@ -461,7 +463,7 @@ static void duoram_test(MPCIO &mpcio, yield_t &yield,
                 auto check = A.reconstruct();
                 if (tio.player() == 0) {
                     for (address_t i=0;i<size;++i) {
-                        printf("%04x %016lx\n", i, check[i].ashare);
+                        printf("%04x %016lx\n", i, check[i].share());
                     }
                 }
             }
@@ -506,7 +508,11 @@ void online_main(MPCIO &mpcio, const PRACOptions &opts, char **args)
                 tupleeval_timing(mpcio, yield, opts, args);
             } else if (!strcmp(*args, "duotest")) {
                 ++args;
-                duoram_test(mpcio, yield, opts, args);
+                if (opts.use_xor_db) {
+                    duoram_test<RegXS>(mpcio, yield, opts, args);
+                } else {
+                    duoram_test<RegAS>(mpcio, yield, opts, args);
+                }
             } else {
                 std::cerr << "Unknown mode " << *args << "\n";
             }

+ 2 - 1
options.hpp

@@ -5,9 +5,10 @@ struct PRACOptions {
     bool preprocessing;
     int num_threads;
     bool expand_rdpfs;
+    bool use_xor_db;
 
     PRACOptions() : preprocessing(false), num_threads(1),
-        expand_rdpfs(true) {}
+        expand_rdpfs(true), use_xor_db(false) {}
 };
 
 #endif

+ 4 - 0
prac.cpp

@@ -12,6 +12,7 @@ static void usage(const char *progname)
     std::cerr << "-p: preprocessing mode\n";
     std::cerr << "-t num: use num threads\n";
     std::cerr << "-c: store DPFs compressed (default is expanded)\n";
+    std::cerr << "-x: use XOR-shared database (default is additive)\n";
     std::cerr << "player_num = 0 or 1 for the computational players\n";
     std::cerr << "player_num = 2 for the server player\n";
     std::cerr << "player_addrs is omitted for player 0\n";
@@ -97,6 +98,9 @@ int main(int argc, char **argv)
         } else if (!strcmp("-c", *args)) {
             opts.expand_rdpfs = false;
             ++args;
+        } else if (!strcmp("-x", *args)) {
+            opts.use_xor_db = true;
+            ++args;
         }
     }
     if (*args == NULL) {

+ 18 - 77
rdpf.hpp

@@ -201,51 +201,18 @@ struct RDPFTriple {
     node descend(const node &parent, nbits_t parentdepth,
         bit_t whichchild, size_t &op_counter) const;
 
-    // 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}
-    inline std::tuple<RegAS,RegAS,RegAS> scaled_sum() const {
-        return std::make_tuple(dpf[0].scaled_sum, dpf[1].scaled_sum,
-            dpf[2].scaled_sum);
-    }
+    // Templated versions of functions to get DPF components and outputs
+    // so that the appropriate one can be selected with a template
+    // parameter
 
-    // XOR share of the scaling value M_xs such that the high words
-    // of the leaf values for P0 and P1 XOR to M_xs * e_{target}
-    inline std::tuple<RegXS,RegXS,RegXS> scaled_xor() const {
-        return std::make_tuple(dpf[0].scaled_xor, dpf[1].scaled_xor,
-            dpf[2].scaled_xor);
-    }
+    template <typename T>
+    inline std::tuple<T,T,T> scaled_value() const;
 
-    // Get the bit-shared unit vector entry from the leaf node
-    inline std::tuple<RegBS,RegBS,RegBS> unit_bs(node leaf) const {
-        return std::make_tuple(
-            dpf[0].unit_bs(std::get<0>(leaf)),
-            dpf[1].unit_bs(std::get<1>(leaf)),
-            dpf[2].unit_bs(std::get<2>(leaf)));
-    }
+    template <typename T>
+    inline std::tuple<T,T,T> unit(node leaf) const;
 
-    // Get the additive-shared unit vector entry from the leaf node
-    inline std::tuple<RegAS,RegAS,RegAS> unit_as(node leaf) const {
-        return std::make_tuple(
-            dpf[0].unit_as(std::get<0>(leaf)),
-            dpf[1].unit_as(std::get<1>(leaf)),
-            dpf[2].unit_as(std::get<2>(leaf)));
-    }
-
-    // Get the XOR-shared scaled vector entry from the leaf ndoe
-    inline std::tuple<RegXS,RegXS,RegXS> scaled_xs(node leaf) const {
-        return std::make_tuple(
-            dpf[0].scaled_xs(std::get<0>(leaf)),
-            dpf[1].scaled_xs(std::get<1>(leaf)),
-            dpf[2].scaled_xs(std::get<2>(leaf)));
-    }
-
-    // Get the additive-shared scaled vector entry from the leaf node
-    inline std::tuple<RegAS,RegAS,RegAS> scaled_as(node leaf) const {
-        return std::make_tuple(
-            dpf[0].scaled_as(std::get<0>(leaf)),
-            dpf[1].scaled_as(std::get<1>(leaf)),
-            dpf[2].scaled_as(std::get<2>(leaf)));
-    }
+    template <typename T>
+    inline std::tuple<T,T,T> scaled(node leaf) const;
 };
 
 struct RDPFPair {
@@ -288,45 +255,19 @@ struct RDPFPair {
     node descend(const node &parent, nbits_t parentdepth,
         bit_t whichchild, size_t &op_counter) const;
 
-    // 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}
-    inline std::tuple<RegAS,RegAS> scaled_sum() const {
-        return std::make_tuple(dpf[0].scaled_sum, dpf[1].scaled_sum);
-    }
-
-    // XOR share of the scaling value M_xs such that the high words
-    // of the leaf values for P0 and P1 XOR to M_xs * e_{target}
-    inline std::tuple<RegXS,RegXS> scaled_xor() const {
-        return std::make_tuple(dpf[0].scaled_xor, dpf[1].scaled_xor);
-    }
+    // Templated versions of functions to get DPF components and outputs
+    // so that the appropriate one can be selected with a template
+    // parameter
 
-    // Get the bit-shared unit vector entry from the leaf node
-    inline std::tuple<RegBS,RegBS> unit_bs(node leaf) const {
-        return std::make_tuple(
-            dpf[0].unit_bs(std::get<0>(leaf)),
-            dpf[1].unit_bs(std::get<1>(leaf)));
-    }
+    template <typename T>
+    inline std::tuple<T,T> scaled_value() const;
 
-    // Get the additive-shared unit vector entry from the leaf node
-    inline std::tuple<RegAS,RegAS> unit_as(node leaf) const {
-        return std::make_tuple(
-            dpf[0].unit_as(std::get<0>(leaf)),
-            dpf[1].unit_as(std::get<1>(leaf)));
-    }
+    template <typename T>
+    inline std::tuple<T,T> unit(node leaf) const;
 
-    // Get the XOR-shared scaled vector entry from the leaf ndoe
-    inline std::tuple<RegXS,RegXS> scaled_xs(node leaf) const {
-        return std::make_tuple(
-            dpf[0].scaled_xs(std::get<0>(leaf)),
-            dpf[1].scaled_xs(std::get<1>(leaf)));
-    }
+    template <typename T>
+    inline std::tuple<T,T> scaled(node leaf) const;
 
-    // Get the additive-shared scaled vector entry from the leaf node
-    inline std::tuple<RegAS,RegAS> scaled_as(node leaf) const {
-        return std::make_tuple(
-            dpf[0].scaled_as(std::get<0>(leaf)),
-            dpf[1].scaled_as(std::get<1>(leaf)));
-    }
 };
 
 #include "rdpf.tcc"

+ 98 - 0
rdpf.tcc

@@ -85,6 +85,104 @@ typename T::node StreamEval<T>::next()
     return leaf;
 }
 
+// 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}
+template <>
+inline std::tuple<RegAS,RegAS,RegAS> RDPFTriple::scaled_value<RegAS>() const {
+    return std::make_tuple(dpf[0].scaled_sum, dpf[1].scaled_sum,
+        dpf[2].scaled_sum);
+}
+
+// XOR share of the scaling value M_xs such that the high words
+// of the leaf values for P0 and P1 XOR to M_xs * e_{target}
+template <>
+inline std::tuple<RegXS,RegXS,RegXS> RDPFTriple::scaled_value<RegXS>() const {
+    return std::make_tuple(dpf[0].scaled_xor, dpf[1].scaled_xor,
+        dpf[2].scaled_xor);
+}
+
+// Get the bit-shared unit vector entry from the leaf node
+template <>
+inline std::tuple<RegXS,RegXS,RegXS> RDPFTriple::unit<RegXS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].unit_bs(std::get<0>(leaf)),
+        dpf[1].unit_bs(std::get<1>(leaf)),
+        dpf[2].unit_bs(std::get<2>(leaf)));
+}
+
+// Get the additive-shared unit vector entry from the leaf node
+template <>
+inline std::tuple<RegAS,RegAS,RegAS> RDPFTriple::unit<RegAS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].unit_as(std::get<0>(leaf)),
+        dpf[1].unit_as(std::get<1>(leaf)),
+        dpf[2].unit_as(std::get<2>(leaf)));
+}
+
+// Get the XOR-shared scaled vector entry from the leaf ndoe
+template <>
+inline std::tuple<RegXS,RegXS,RegXS> RDPFTriple::scaled<RegXS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].scaled_xs(std::get<0>(leaf)),
+        dpf[1].scaled_xs(std::get<1>(leaf)),
+        dpf[2].scaled_xs(std::get<2>(leaf)));
+}
+
+// Get the additive-shared scaled vector entry from the leaf node
+template <>
+inline std::tuple<RegAS,RegAS,RegAS> RDPFTriple::scaled<RegAS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].scaled_as(std::get<0>(leaf)),
+        dpf[1].scaled_as(std::get<1>(leaf)),
+        dpf[2].scaled_as(std::get<2>(leaf)));
+}
+
+// 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}
+template <>
+inline std::tuple<RegAS,RegAS> RDPFPair::scaled_value<RegAS>() const {
+    return std::make_tuple(dpf[0].scaled_sum, dpf[1].scaled_sum);
+}
+
+// XOR share of the scaling value M_xs such that the high words
+// of the leaf values for P0 and P1 XOR to M_xs * e_{target}
+template <>
+inline std::tuple<RegXS,RegXS> RDPFPair::scaled_value<RegXS>() const {
+    return std::make_tuple(dpf[0].scaled_xor, dpf[1].scaled_xor);
+}
+
+// Get the bit-shared unit vector entry from the leaf node
+template <>
+inline std::tuple<RegXS,RegXS> RDPFPair::unit<RegXS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].unit_bs(std::get<0>(leaf)),
+        dpf[1].unit_bs(std::get<1>(leaf)));
+}
+
+// Get the additive-shared unit vector entry from the leaf node
+template <>
+inline std::tuple<RegAS,RegAS> RDPFPair::unit<RegAS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].unit_as(std::get<0>(leaf)),
+        dpf[1].unit_as(std::get<1>(leaf)));
+}
+
+// Get the XOR-shared scaled vector entry from the leaf ndoe
+template <>
+inline std::tuple<RegXS,RegXS> RDPFPair::scaled<RegXS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].scaled_xs(std::get<0>(leaf)),
+        dpf[1].scaled_xs(std::get<1>(leaf)));
+}
+
+// Get the additive-shared scaled vector entry from the leaf node
+template <>
+inline std::tuple<RegAS,RegAS> RDPFPair::scaled<RegAS>(node leaf) const {
+    return std::make_tuple(
+        dpf[0].scaled_as(std::get<0>(leaf)),
+        dpf[1].scaled_as(std::get<1>(leaf)));
+}
+
 // I/O for RDPFs
 
 template <typename T>

+ 42 - 0
types.hpp

@@ -49,6 +49,7 @@ struct RegAS {
     RegAS() : ashare(0) {}
 
     inline value_t share() const { return ashare; }
+    inline void set(value_t s) { ashare = s; }
 
     // Set each side's share to a random value nbits bits long
     inline void randomize(size_t nbits = VALUE_BITS) {
@@ -118,6 +119,7 @@ struct RegBS {
     RegBS() : bshare(0) {}
 
     inline bit_t share() const { return bshare; }
+    inline void set(bit_t s) { bshare = s; }
 
     // Set each side's share to a random bit
     inline void randomize() {
@@ -143,8 +145,10 @@ struct RegXS {
     value_t xshare;
 
     RegXS() : xshare(0) {}
+    RegXS(const RegBS &b) { xshare = b.bshare ? ~0 : 0; }
 
     inline value_t share() const { return xshare; }
+    inline void set(value_t s) { xshare = s; }
 
     // Set each side's share to a random value nbits bits long
     inline void randomize(size_t nbits = VALUE_BITS) {
@@ -153,6 +157,44 @@ struct RegXS {
         xshare &= mask;
     }
 
+    // For RegXS, + and * should be interpreted bitwise; that is, + is
+    // really XOR and * is really AND.  - is also XOR (the same as +).
+
+    // We also include actual XOR operators for convenience
+
+    inline RegXS &operator+=(const RegXS &rhs) {
+        this->xshare ^= rhs.xshare;
+        return *this;
+    }
+
+    inline RegXS operator+(const RegXS &rhs) const {
+        RegXS res = *this;
+        res += rhs;
+        return res;
+    }
+
+    inline RegXS &operator-=(const RegXS &rhs) {
+        this->xshare ^= rhs.xshare;
+        return *this;
+    }
+
+    inline RegXS operator-(const RegXS &rhs) const {
+        RegXS res = *this;
+        res -= rhs;
+        return res;
+    }
+
+    inline RegXS &operator*=(value_t rhs) {
+        this->xshare &= rhs;
+        return *this;
+    }
+
+    inline RegXS operator*(value_t rhs) const {
+        RegXS res = *this;
+        res *= rhs;
+        return res;
+    }
+
     inline RegXS &operator^=(const RegXS &rhs) {
         this->xshare ^= rhs.xshare;
         return *this;