Browse Source

Change AndTriple to SelectTriple

In a SelectTriple, the X component is a single bit, and Y and Z are
DPFnode (128-bit) values, but mathematically it's the same as a
MultTriple.
Ian Goldberg 2 years ago
parent
commit
05f8e4a23d
5 changed files with 49 additions and 32 deletions
  1. 24 14
      mpcio.cpp
  2. 1 1
      mpcio.hpp
  3. 7 5
      mpcops.cpp
  4. 7 6
      rdpf.hpp
  5. 10 6
      types.hpp

+ 24 - 14
mpcio.cpp

@@ -1,4 +1,5 @@
 #include "mpcio.hpp"
+#include "bitutils.hpp"
 
 template<typename T>
 PreCompStorage<T>::PreCompStorage(unsigned player, bool preprocessing,
@@ -466,31 +467,40 @@ HalfTriple MPCTIO::halftriple()
     return val;
 }
 
-AndTriple MPCTIO::andtriple()
+SelectTriple MPCTIO::selecttriple()
 {
-    AndTriple val;
+    SelectTriple val;
     if (mpcio.player < 2) {
         MPCPeerIO &mpcpio = static_cast<MPCPeerIO&>(mpcio);
         if (mpcpio.preprocessing) {
-            recv_server(&val, sizeof(val));
+            recv_server(&val.X, sizeof(val.X));
+            recv_server(&val.Y, sizeof(val.Y));
+            recv_server(&val.Z, sizeof(val.Z));
         } else {
-            std::cerr << "Attempted to read AndTriple in online phase\n";
+            std::cerr << "Attempted to read SelectTriple in online phase\n";
         }
     } else if (mpcio.preprocessing) {
         // Create triples (X0,Y0,Z0),(X1,Y1,Z1) such that
-        // (X0&Y1 ^ Y0&X1) = (Z0^Z1)
-        DPFnode X0, Y0, Z0, X1, Y1, Z1;
-        arc4random_buf(&X0, sizeof(X0));
+        // (X0*Y1 ^ Y0*X1) = (Z0^Z1)
+        bit_t X0, X1;
+        DPFnode Y0, Z0, Y1, Z1;
+        X0 = arc4random() & 1;
         arc4random_buf(&Y0, sizeof(Y0));
         arc4random_buf(&Z0, sizeof(Z0));
-        arc4random_buf(&X1, sizeof(X1));
+        X1 = arc4random() & 1;
         arc4random_buf(&Y1, sizeof(Y1));
-        Z1 = ((X0 & Y1) ^ (X1 & Y0)) ^ Z0;
-        AndTriple T0, T1;
-        T0 = std::make_tuple(X0, Y0, Z0);
-        T1 = std::make_tuple(X1, Y1, Z1);
-        queue_p0(&T0, sizeof(T0));
-        queue_p1(&T1, sizeof(T1));
+        DPFnode X0ext, X1ext;
+        // Sign-extend X0 and X1 (so that 0 -> 0000...0 and
+        // 1 -> 1111...1)
+        X0ext = if128_mask[X0];
+        X1ext = if128_mask[X1];
+        Z1 = ((X0ext & Y1) ^ (X1ext & Y0)) ^ Z0;
+        queue_p0(&X0, sizeof(X0));
+        queue_p0(&Y0, sizeof(Y0));
+        queue_p0(&Z0, sizeof(Z0));
+        queue_p1(&X1, sizeof(X1));
+        queue_p1(&Y1, sizeof(Y1));
+        queue_p1(&Z1, sizeof(Z1));
     }
     return val;
 }

+ 1 - 1
mpcio.hpp

@@ -274,7 +274,7 @@ public:
 
     MultTriple triple();
     HalfTriple halftriple();
-    AndTriple andtriple();
+    SelectTriple selecttriple();
 
     // Accessors
 

+ 7 - 5
mpcops.cpp

@@ -215,9 +215,9 @@ void mpc_reconstruct_choice(MPCTIO &tio, yield_t &yield,
     DPFnode fext = if128_mask[f.bshare];
 
     // Compute XOR shares of f & (x ^ y)
-    auto [X, Y, Z] = tio.andtriple();
+    auto [X, Y, Z] = tio.selecttriple();
 
-    DPFnode blind_f = fext ^ X;
+    bit_t blind_f = f.bshare ^ X;
     DPFnode d = x ^ y;
     DPFnode blind_d = d ^ Y;
 
@@ -228,13 +228,15 @@ void mpc_reconstruct_choice(MPCTIO &tio, yield_t &yield,
     yield();
 
     // Read the peer's values
-    DPFnode peer_blind_f, peer_blind_d;
+    bit_t peer_blind_f = 0;
+    DPFnode peer_blind_d;
     tio.recv_peer(&peer_blind_f, sizeof(peer_blind_f));
     tio.recv_peer(&peer_blind_d, sizeof(peer_blind_d));
 
-    // Compute _our share_ of f ? x : y = (f & (x ^ y))^x
+    // Compute _our share_ of f ? x : y = (f * (x ^ y))^x
+    DPFnode peer_blind_fext = if128_mask[peer_blind_f];
     DPFnode zshare =
-            (fext & peer_blind_d) ^ (Y & peer_blind_f) ^
+            (fext & peer_blind_d) ^ (Y & peer_blind_fext) ^
             (fext & d) ^ (Z ^ x);
 
     // Now exchange shares

+ 7 - 6
rdpf.hpp

@@ -27,15 +27,16 @@ struct RDPF {
 
     // Construct a DPF with the given (XOR-shared) target location, and
     // of the given depth, to be used for random-access memory reads and
-    // writes.  The DPF is construction collaboratively by P0 and P1,
-    // with the server P2 helping by providing various kinds of
-    // correlated randomness, such as MultTriples and AndTriples.
+    // writes.  The DPF is constructed collaboratively by P0 and P1,
+    // with the server P2 helping by providing correlated randomness,
+    // such as SelectTriples.
     //
     // Cost:
-    // (3 DPFnode + 1 byte)*depth + 1 word communication in
+    // (2 DPFnode + 2 bytes)*depth + 1 word communication in
     // 2*depth + 1 messages
-    // 3*depth DPFnode communication from P2 to each party
-    // 2^{depth+1}-2 local AES operations
+    // (2 DPFnode + 1 byte)*depth communication from P2 to each party
+    // 2^{depth+1}-2 local AES operations for P0,P1
+    // 0 local AES operations for P2
     RDPF(MPCTIO &tio, yield_t &yield,
         RegXS target, nbits_t depth);
 };

+ 10 - 6
types.hpp

@@ -190,12 +190,16 @@ using HalfTriple = std::tuple<value_t, value_t>;
 
 using DPFnode = __m128i;
 
-// An AND triple is a triple of (X0,Y0,Z0) of DPFnodes held by P0 (and
-// correspondingly (X1,Y1,Z1) held by P1), with all values random, but
-// subject to the relation that (X0&Y1) ^ (Y0&X1) = Z0^Z1.  These are
-// only used while creating RDPFs in the preprocessing phase, so we
-// never need to store them.
+// A Select triple is a triple of (X0,Y0,Z0) where X0 is a bit and Y0
+// and Z0 are DPFnodes held by P0 (and correspondingly (X1,Y1,Z1) held
+// by P1), with all values random, but subject to the relation that
+// (X0*Y1) ^ (Y0*X1) = Z0^Z1.  These are only used while creating RDPFs
+// in the preprocessing phase, so we never need to store them.  This is
+// a struct instead of a tuple for alignment reasons.
 
-using AndTriple = std::tuple<DPFnode, DPFnode, DPFnode>;
+struct SelectTriple {
+    bit_t X;
+    DPFnode Y, Z;
+};
 
 #endif