Browse Source

Start constructing DPFs: the correction words

Ian Goldberg 1 year ago
parent
commit
41ca42d01b
6 changed files with 170 additions and 10 deletions
  1. 31 0
      mpcio.cpp
  2. 1 0
      mpcio.hpp
  3. 51 0
      mpcops.cpp
  4. 9 0
      mpcops.hpp
  5. 62 1
      rdpf.cpp
  6. 16 9
      types.hpp

+ 31 - 0
mpcio.cpp

@@ -466,6 +466,37 @@ HalfTriple MPCTIO::halftriple()
     return val;
 }
 
+AndTriple MPCTIO::andtriple()
+{
+    AndTriple val;
+    if (mpcio.player < 2) {
+        MPCPeerIO &mpcpio = static_cast<MPCPeerIO&>(mpcio);
+        if (mpcpio.preprocessing) {
+            recv_server(&val, sizeof(val));
+        } else {
+            std::cerr << "Attempted to read AndTriple 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));
+        arc4random_buf(&Y0, sizeof(Y0));
+        arc4random_buf(&Z0, sizeof(Z0));
+        arc4random_buf(&X1, sizeof(X1));
+        arc4random_buf(&Y1, sizeof(Y1));
+        Z1 = _mm_xor_si128(
+            _mm_xor_si128(_mm_and_si128(X0, Y1), _mm_and_si128(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));
+    }
+    return val;
+}
+
 // The port number for the P1 -> P0 connection
 static const unsigned short port_p1_p0 = 2115;
 

+ 1 - 0
mpcio.hpp

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

+ 51 - 0
mpcops.cpp

@@ -1,4 +1,5 @@
 #include "mpcops.hpp"
+#include "bitutils.hpp"
 
 // P0 and P1 both hold additive shares of x (shares are x0 and x1) and y
 // (shares are y0 and y1); compute additive shares of z = x*y =
@@ -200,3 +201,53 @@ void mpc_xs_to_as(MPCTIO &tio, yield_t &yield,
     }
     as_x.ashare = (xs_x.xshare - as_C) & mask;
 }
+
+// P0 and P1 hold bit shares of f, and DPFnode XOR shares x0,y0 and
+// x1,y1 of x and y.  Set z to x=x0^x1 if f=0 and to y=y0^y1 if f=1.
+//
+// Cost:
+// 6 64-bit words sent in 2 messages
+// consumes one AndTriple
+void mpc_reconstruct_choice(MPCTIO &tio, yield_t &yield,
+    DPFnode &z, RegBS f, DPFnode x, DPFnode y)
+{
+    // Sign-extend f (so 0 -> 0000...0; 1 -> 1111...1)
+    DPFnode fext = if128_mask[f.bshare];
+
+    // Compute XOR shares of f & (x ^ y)
+    auto [X, Y, Z] = tio.andtriple();
+
+    DPFnode blind_f = _mm_xor_si128(fext, X);
+    DPFnode d = _mm_xor_si128(x, y);
+    DPFnode blind_d = _mm_xor_si128(d, Y);
+
+    // Send the blinded values
+    tio.queue_peer(&blind_f, sizeof(blind_f));
+    tio.queue_peer(&blind_d, sizeof(blind_d));
+
+    yield();
+
+    // Read the peer's values
+    DPFnode peer_blind_f, 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
+    DPFnode zshare = _mm_xor_si128(
+        _mm_xor_si128(
+            _mm_xor_si128(
+                _mm_and_si128(fext, peer_blind_d),
+                _mm_and_si128(Y, peer_blind_f)),
+            _mm_and_si128(fext, d)),
+        _mm_xor_si128(Z, x));
+
+    // Now exchange shares
+    tio.queue_peer(&zshare, sizeof(zshare));
+
+    yield();
+
+    DPFnode peer_zshare;
+    tio.recv_peer(&peer_zshare, sizeof(peer_zshare));
+
+    z = _mm_xor_si128(zshare, peer_zshare);
+}

+ 9 - 0
mpcops.hpp

@@ -86,4 +86,13 @@ void mpc_xs_to_as(MPCTIO &tio, yield_t &yield,
     RegAS &as_x, RegXS xs_x,
     nbits_t nbits = VALUE_BITS);
 
+// P0 and P1 hold bit shares of f, and DPFnode XOR shares x0,y0 and
+// x1,y1 of x and y.  Set z to x=x0^x1 if f=0 and to y=y0^y1 if f=1.
+//
+// Cost:
+// 6 64-bit words sent in 2 messages
+// consumes one AndTriple
+void mpc_reconstruct_choice(MPCTIO &tio, yield_t &yield,
+    DPFnode &z, RegBS f, DPFnode x, DPFnode y);
+
 #endif

+ 62 - 1
rdpf.cpp

@@ -2,9 +2,25 @@
 
 #include "rdpf.hpp"
 #include "bitutils.hpp"
+#include "mpcops.hpp"
 #include "aes.hpp"
 #include "prg.hpp"
 
+static void dump_node(DPFnode node, const char *label = NULL)
+{
+    if (label) printf("%s: ", label);
+    for(int i=0;i<16;++i) { printf("%02x", ((unsigned char *)&node)[15-i]); } printf("\n");
+}
+
+static void dump_level(DPFnode *nodes, size_t num, const char *label = NULL)
+{
+    if (label) printf("%s:\n", label);
+    for (size_t i=0;i<num;++i) {
+        dump_node(nodes[i]);
+    }
+    printf("\n");
+}
+
 // 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,
@@ -20,7 +36,52 @@ RDPF::RDPF(MPCTIO &tio, yield_t &yield,
     arc4random_buf(&seed, sizeof(seed));
     // Ensure the flag bits (the lsb of each node) are different
     seed = set_lsb(seed, !!player);
-    printf("seed: "); for(int i=0;i<16;++i) { printf("%02x", ((unsigned char *)&seed)[15-i]); } printf("\n");
+    cfbits = 0;
+
+    // The root level is just the seed
+    nbits_t level = 0;
+    DPFnode *curlevel = NULL;
+    DPFnode *nextlevel = new DPFnode[1];
+    nextlevel[0] = seed;
+
+    // Construct each intermediate level
+    while(level < depth - 1) {
+        delete[] curlevel;
+        curlevel = nextlevel;
+        nextlevel = new DPFnode[1<<(level+1)];
+        // Invariant: curlevel has 2^level elements; nextlevel has
+        // 2^{level+1} elements
+
+        // The bit-shared choice bit is bit (depth-level-1) of the
+        // XOR-shared target index
+        RegBS bs_choice = target.bit(depth-level-1);
+        size_t curlevel_size = (size_t(1)<<level);
+        DPFnode L = _mm_setzero_si128();
+        DPFnode R = _mm_setzero_si128();
+        if (player < 2) {
+            for(size_t i=0;i<curlevel_size;++i) {
+                prgboth(nextlevel[2*i], nextlevel[2*i+1], curlevel[i], aesops);
+                L = _mm_xor_si128(L, nextlevel[2*i]);
+                R = _mm_xor_si128(R, nextlevel[2*i+1]);
+            }
+        }
+        DPFnode CW;
+        mpc_reconstruct_choice(tio, yield, CW, bs_choice, R, L);
+        if (player < 2) {
+            for(size_t i=0;i<curlevel_size;++i) {
+                bool flag = get_lsb(curlevel[i]);
+                nextlevel[2*i] = xor_if(nextlevel[2*i], CW, flag);
+                nextlevel[2*i+1] = xor_if(nextlevel[2*i+1], CW, flag);
+            }
+            printf("%d\n", bs_choice.bshare);
+            dump_level(nextlevel, curlevel_size<<1);
+            cw.push_back(CW);
+        }
+
+        ++level;
+    }
+
+    // We don't need to store the last level
 
     AESkey prgkey;
     __m128i key = _mm_set_epi64x(314159265, 271828182);

+ 16 - 9
types.hpp

@@ -98,6 +98,17 @@ struct RegAS {
     }
 };
 
+// The type of a register holding a bit share
+struct RegBS {
+    bit_t bshare;
+
+    // Set each side's share to a random bit
+    inline void randomize() {
+        arc4random_buf(&bshare, sizeof(bshare));
+        bshare &= 1;
+    }
+};
+
 // The type of a register holding an XOR share of a value
 struct RegXS {
     value_t xshare;
@@ -130,16 +141,12 @@ struct RegXS {
         res &= mask;
         return res;
     }
-};
-
-// The type of a register holding a bit share
-struct RegBS {
-    bit_t bshare;
 
-    // Set each side's share to a random bit
-    inline void randomize() {
-        arc4random_buf(&bshare, sizeof(bshare));
-        bshare &= 1;
+    // Extract a bit share of bit bitnum of the XOR-shared register
+    inline RegBS bit(bit_t bitnum) const {
+        RegBS bs;
+        bs.bshare = !!(xshare & (size_t(1)<<bitnum));
+        return bs;
     }
 };