Browse Source

Add support for AND triples and value_t SelectTriples

Ian Goldberg 1 year ago
parent
commit
240782591d
5 changed files with 191 additions and 8 deletions
  1. 2 0
      README.md
  2. 91 0
      mpcio.cpp
  3. 5 0
      mpcio.hpp
  4. 65 8
      preproc.cpp
  5. 28 0
      types.hpp

+ 2 - 0
README.md

@@ -54,6 +54,8 @@ The args in preprocessing mode are each of the form <code>_type_:_num_</code> to
 
   - `m`: a multiplication triple
   - `h`: a multiplication half-triple
+  - `a`: an AND triple
+  - `s`: a select triple
   - <code>r*d*</code>: A DPF of depth <code>_d_</code> for random accesses to memory (RDPF).  A DPF of depth _d_ can be used to process 2<sup>_d_</sup> memory locations.
   - `c`: a DPF for comparisons (CDPF)
 

+ 91 - 0
mpcio.cpp

@@ -291,6 +291,12 @@ MPCPeerIO::MPCPeerIO(unsigned player, ProcessingMode mode,
     for (unsigned i=0; i<num_threads; ++i) {
         halftriples.emplace_back(player, mode, "halves", i);
     }
+    for (unsigned i=0; i<num_threads; ++i) {
+        andtriples.emplace_back(player, mode, "ands", i);
+    }
+    for (unsigned i=0; i<num_threads; ++i) {
+        valselecttriples.emplace_back(player, mode, "selects", i);
+    }
     rdpftriples.resize(num_threads);
     for (unsigned i=0; i<num_threads; ++i) {
         for (unsigned depth=1; depth<=ADDRESS_MAX_BITS; ++depth) {
@@ -325,6 +331,14 @@ void MPCPeerIO::dump_precomp_stats(std::ostream &os)
         if (cnt > 0) {
             os << " h:" << cnt;
         }
+        cnt = andtriples[i].get_stats();
+        if (cnt > 0) {
+            os << " a:" << cnt;
+        }
+        cnt = valselecttriples[i].get_stats();
+        if (cnt > 0) {
+            os << " s:" << cnt;
+        }
         for (nbits_t depth=1; depth<=ADDRESS_MAX_BITS; ++depth) {
             cnt = rdpftriples[i][depth-1].get_stats();
             if (cnt > 0) {
@@ -344,6 +358,8 @@ void MPCPeerIO::reset_precomp_stats()
     for (size_t i=0; i<multtriples.size(); ++i) {
         multtriples[i].reset_stats();
         halftriples[i].reset_stats();
+        andtriples[i].reset_stats();
+        valselecttriples[i].reset_stats();
         for (nbits_t depth=1; depth<=ADDRESS_MAX_BITS; ++depth) {
             rdpftriples[i][depth-1].reset_stats();
         }
@@ -650,6 +666,38 @@ HalfTriple MPCTIO::halftriple(yield_t &yield, bool tally)
     return val;
 }
 
+MultTriple MPCTIO::andtriple(yield_t &yield)
+{
+    AndTriple val;
+    if (mpcio.player < 2) {
+        MPCPeerIO &mpcpio = static_cast<MPCPeerIO&>(mpcio);
+        if (mpcpio.mode != MODE_ONLINE) {
+            yield();
+            recv_server(&val, sizeof(val));
+            mpcpio.andtriples[thread_num].inc();
+        } else {
+            mpcpio.andtriples[thread_num].get(val);
+        }
+    } else if (mpcio.mode != MODE_ONLINE) {
+        // Create AND triples (X0,Y0,Z0),(X1,Y1,Z1) such that
+        // (X0&Y1 ^ Y0&X1) = (Z0^Z1)
+        value_t 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 = (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));
+        yield();
+    }
+    return val;
+}
+
 SelectTriple<DPFnode> MPCTIO::nodeselecttriple(yield_t &yield)
 {
     SelectTriple<DPFnode> val;
@@ -692,6 +740,49 @@ SelectTriple<DPFnode> MPCTIO::nodeselecttriple(yield_t &yield)
     return val;
 }
 
+SelectTriple<value_t> MPCTIO::valselecttriple(yield_t &yield)
+{
+    SelectTriple<value_t> val;
+    if (mpcio.player < 2) {
+        MPCPeerIO &mpcpio = static_cast<MPCPeerIO&>(mpcio);
+        if (mpcpio.mode != MODE_ONLINE) {
+            uint8_t Xbyte;
+            yield();
+            recv_server(&Xbyte, sizeof(Xbyte));
+            val.X = Xbyte & 1;
+            recv_server(&val.Y, sizeof(val.Y));
+            recv_server(&val.Z, sizeof(val.Z));
+            mpcpio.valselecttriples[thread_num].inc();
+        } else {
+            mpcpio.valselecttriples[thread_num].get(val);
+        }
+    } else if (mpcio.mode != MODE_ONLINE) {
+        // Create triples (X0,Y0,Z0),(X1,Y1,Z1) such that
+        // (X0*Y1 ^ Y0*X1) = (Z0^Z1)
+        bit_t X0, X1;
+        value_t Y0, Z0, Y1, Z1;
+        X0 = arc4random() & 1;
+        arc4random_buf(&Y0, sizeof(Y0));
+        arc4random_buf(&Z0, sizeof(Z0));
+        X1 = arc4random() & 1;
+        arc4random_buf(&Y1, sizeof(Y1));
+        value_t X0ext, X1ext;
+        // Sign-extend X0 and X1 (so that 0 -> 0000...0 and
+        // 1 -> 1111...1)
+        X0ext = -value_t(X0);
+        X1ext = -value_t(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));
+        yield();
+    }
+    return val;
+}
+
 // Only computational peers call this; the server should be calling
 // rdpfpair() at the same time
 RDPFTriple MPCTIO::rdpftriple(yield_t &yield, nbits_t depth,

+ 5 - 0
mpcio.hpp

@@ -209,6 +209,9 @@ struct MPCPeerIO : public MPCIO {
     std::deque<MPCSingleIO> serverios;
     std::vector<PreCompStorage<MultTriple, MultTripleName>> multtriples;
     std::vector<PreCompStorage<HalfTriple, HalfTripleName>> halftriples;
+    std::vector<PreCompStorage<AndTriple, AndTripleName>> andtriples;
+    std::vector<PreCompStorage<
+        SelectTriple<value_t>, ValSelectTripleName>> valselecttriples;
     std::vector<PreCompStorage<CDPF, CDPFName>> cdpfs;
     // The outer vector is (like above) one item per thread
     // The inner array is indexed by DPF depth (depth d is at entry d-1)
@@ -372,7 +375,9 @@ public:
 
     MultTriple multtriple(yield_t &yield);
     HalfTriple halftriple(yield_t &yield, bool tally=true);
+    AndTriple andtriple(yield_t &yield);
     SelectTriple<DPFnode> nodeselecttriple(yield_t &yield);
+    SelectTriple<value_t> valselecttriple(yield_t &yield);
 
     // These ones only work during the online phase
     // Computational peers call:

+ 65 - 8
preproc.cpp

@@ -67,12 +67,14 @@ void Openfiles::closeall()
 // data is:
 //
 // One byte: type
-//   0x80: Multiplication triple
-//   0x81: Multiplication half-triple
 //   0x01 to 0x30: RAM DPF of that depth
 //   0x40: Comparison DPF
-//   0x82: Counter (for testing)
-//   0x83: Set number of CPU threads for this communication thread
+//   0x80: Multiplication triple
+//   0x81: Multiplication half-triple
+//   0x82: AND triple
+//   0x83: Select triple
+//   0x8e: Counter (for testing)
+//   0x8f: Set number of CPU threads for this communication thread
 //   0x00: End of preprocessing
 //
 // Four bytes: number of objects of that type (not sent for type == 0x00)
@@ -122,6 +124,33 @@ void preprocessing_comp(MPCIO &mpcio, const PRACOptions &opts, char **args)
                                 halffile.os() << H;
                             });
                     }
+                } else if (type == 0x82) {
+                    // AND triples
+                    auto andfile = ofiles.open("ands",
+                        mpcio.player, thread_num);
+
+                    for (unsigned int i=0; i<num; ++i) {
+                        coroutines.emplace_back(
+                            [&tio, andfile](yield_t &yield) {
+                                yield();
+                                AndTriple A = tio.andtriple(yield);
+                                andfile.os() << A;
+                            });
+                    }
+                } else if (type == 0x83) {
+                    // Select triples
+                    auto selfile = ofiles.open("selects",
+                        mpcio.player, thread_num);
+
+                    for (unsigned int i=0; i<num; ++i) {
+                        coroutines.emplace_back(
+                            [&tio, selfile](yield_t &yield) {
+                                yield();
+                                SelectTriple<value_t> S =
+                                    tio.valselecttriple(yield);
+                                selfile.os() << S;
+                            });
+                    }
                 } else if (type >= 0x01 && type <= 0x30) {
                     // RAM DPFs
                     auto tripfile = ofiles.open("rdpf",
@@ -155,7 +184,7 @@ void preprocessing_comp(MPCIO &mpcio, const PRACOptions &opts, char **args)
                                 cdpffile.os() << C;
                             });
                     }
-                } else if (type == 0x82) {
+                } else if (type == 0x8e) {
                     coroutines.emplace_back(
                         [&tio, num](yield_t &yield) {
                             yield();
@@ -174,7 +203,7 @@ void preprocessing_comp(MPCIO &mpcio, const PRACOptions &opts, char **args)
                                 }
                             }
                         });
-                } else if (type == 0x83) {
+                } else if (type == 0x8f) {
                     tio.cpu_nthreads(num);
                 }
             }
@@ -252,6 +281,34 @@ void preprocessing_server(MPCServerIO &mpcsrvio, const PRACOptions &opts, char *
                                 stio.halftriple(yield);
                             });
                     }
+                } else if (!strcmp(type, "a")) {
+                    unsigned char typetag = 0x82;
+                    stio.queue_p0(&typetag, 1);
+                    stio.queue_p0(&num, 4);
+                    stio.queue_p1(&typetag, 1);
+                    stio.queue_p1(&num, 4);
+
+                    for (unsigned int i=0; i<num; ++i) {
+                        coroutines.emplace_back(
+                            [&stio](yield_t &yield) {
+                                yield();
+                                stio.andtriple(yield);
+                            });
+                    }
+                } else if (!strcmp(type, "s")) {
+                    unsigned char typetag = 0x83;
+                    stio.queue_p0(&typetag, 1);
+                    stio.queue_p0(&num, 4);
+                    stio.queue_p1(&typetag, 1);
+                    stio.queue_p1(&num, 4);
+
+                    for (unsigned int i=0; i<num; ++i) {
+                        coroutines.emplace_back(
+                            [&stio](yield_t &yield) {
+                                yield();
+                                stio.valselecttriple(yield);
+                            });
+                    }
                 } else if (type[0] == 'r') {
                     int depth = atoi(type+1);
                     if (depth < 1 || depth > 48) {
@@ -299,7 +356,7 @@ void preprocessing_server(MPCServerIO &mpcsrvio, const PRACOptions &opts, char *
                             });
                     }
                 } else if (!strcmp(type, "i")) {
-                    unsigned char typetag = 0x82;
+                    unsigned char typetag = 0x8e;
                     stio.queue_p0(&typetag, 1);
                     stio.queue_p0(&num, 4);
                     stio.queue_p1(&typetag, 1);
@@ -325,7 +382,7 @@ void preprocessing_server(MPCServerIO &mpcsrvio, const PRACOptions &opts, char *
                         });
 
                 } else if (!strcmp(type, "p")) {
-                    unsigned char typetag = 0x83;
+                    unsigned char typetag = 0x8f;
                     stio.queue_p0(&typetag, 1);
                     stio.queue_p0(&num, 4);
                     stio.queue_p1(&typetag, 1);

+ 28 - 0
types.hpp

@@ -615,6 +615,13 @@ struct MultTripleName { static constexpr const char *name = "m"; };
 using HalfTriple = std::tuple<value_t, value_t>;
 struct HalfTripleName { static constexpr const char *name = "h"; };
 
+// An AND triple is a triple (X0,Y0,Z0) 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
+
+using AndTriple = std::tuple<value_t, value_t, value_t>;
+struct AndTripleName { static constexpr const char *name = "a"; };
+
 // The type of nodes in a DPF.  This must be at least as many bits as
 // the security parameter, and at least twice as many bits as value_t.
 
@@ -670,6 +677,27 @@ DEFAULT_IO(RegAS)
 DEFAULT_IO(RegXS)
 DEFAULT_IO(MultTriple)
 DEFAULT_IO(HalfTriple)
+// We don't need one for AndTriple because it's exactly the same type as
+// MultTriple
+
+// I/O for SelectTriples
+template <typename T, typename V>
+T& operator>>(T& is, SelectTriple<V> &x)
+{
+    is.read((char *)&x.X, sizeof(x.X));
+    is.read((char *)&x.Y, sizeof(x.Y));
+    is.read((char *)&x.Z, sizeof(x.Z));
+    return is;
+}
+
+template <typename T, typename V>
+T& operator<<(T& os, const SelectTriple<V> &x)
+{
+    os.write((const char *)&x.X, sizeof(x.X));
+    os.write((const char *)&x.Y, sizeof(x.Y));
+    os.write((const char *)&x.Z, sizeof(x.Z));
+    return os;
+}
 
 // And for pairs and triples