Browse Source

Move templated method implementations from rdpf.hpp to rdpf.tcc

No content changes
Ian Goldberg 1 year ago
parent
commit
116a8072e7
3 changed files with 223 additions and 220 deletions
  1. 8 8
      Makefile
  2. 1 212
      rdpf.hpp
  3. 214 0
      rdpf.tcc

+ 8 - 8
Makefile

@@ -27,12 +27,12 @@ depend:
 
 # DO NOT DELETE THIS LINE -- make depend depends on it.
 
-prac.o: mpcio.hpp types.hpp preproc.hpp online.hpp
-mpcio.o: mpcio.hpp types.hpp rdpf.hpp coroutine.hpp bitutils.hpp
-preproc.o: types.hpp coroutine.hpp mpcio.hpp preproc.hpp rdpf.hpp
-preproc.o: bitutils.hpp
-online.o: online.hpp mpcio.hpp types.hpp mpcops.hpp coroutine.hpp rdpf.hpp
-online.o: bitutils.hpp
+prac.o: mpcio.hpp types.hpp preproc.hpp options.hpp online.hpp
+mpcio.o: mpcio.hpp types.hpp rdpf.hpp coroutine.hpp bitutils.hpp rdpf.tcc
+preproc.o: types.hpp coroutine.hpp mpcio.hpp preproc.hpp options.hpp rdpf.hpp
+preproc.o: bitutils.hpp rdpf.tcc
+online.o: online.hpp mpcio.hpp types.hpp options.hpp mpcops.hpp coroutine.hpp
+online.o: rdpf.hpp bitutils.hpp rdpf.tcc
 mpcops.o: mpcops.hpp types.hpp mpcio.hpp coroutine.hpp bitutils.hpp
-rdpf.o: rdpf.hpp mpcio.hpp types.hpp coroutine.hpp bitutils.hpp mpcops.hpp
-rdpf.o: aes.hpp prg.hpp
+rdpf.o: rdpf.hpp mpcio.hpp types.hpp coroutine.hpp bitutils.hpp rdpf.tcc
+rdpf.o: mpcops.hpp aes.hpp prg.hpp

+ 1 - 212
rdpf.hpp

@@ -33,90 +33,6 @@ public:
     typename T::node next();
 };
 
-// Create a StreamEval object that will start its output at index start.
-// It will wrap around to 0 when it hits 2^depth.  If use_expansion
-// is true, then if the DPF has been expanded, just output values
-// from that.  If use_expansion=false or if the DPF has not been
-// expanded, compute the values on the fly.
-template <typename T>
-StreamEval<T>::StreamEval(const T &rdpf, address_t start,
-    size_t &op_counter, bool use_expansion) : rdpf(rdpf),
-    op_counter(op_counter), use_expansion(use_expansion)
-{
-    depth = rdpf.depth();
-    // Prevent overflow of 1<<depth
-    if (depth < ADDRESS_MAX_BITS) {
-        indexmask = (address_t(1)<<depth)-1;
-    } else {
-        indexmask = ~0;
-    }
-    // Record that we haven't actually output the leaf for index start
-    // itself yet
-    nextindex = start;
-    if (use_expansion && rdpf.has_expansion()) {
-        // We just need to keep the counter, not compute anything
-        return;
-    }
-    path.resize(depth);
-    pathindex = start;
-    path[0] = rdpf.get_seed();
-    for (nbits_t i=1;i<depth;++i) {
-        bool dir = !!(pathindex & (address_t(1)<<(depth-i)));
-        path[i] = rdpf.descend(path[i-1], i-1, dir, op_counter);
-    }
-}
-
-template <typename T>
-typename T::node StreamEval<T>::next()
-{
-    if (use_expansion && rdpf.has_expansion()) {
-        // Just use the precomputed values
-        typename T::node leaf = rdpf.get_expansion(nextindex);
-        nextindex = (nextindex + 1) & indexmask;
-        return leaf;
-    }
-    // Invariant: in the first call to next(), nextindex = pathindex.
-    // Otherwise, nextindex = pathindex+1.
-    // Get the XOR of nextindex and pathindex, and strip the low bit.
-    // If nextindex and pathindex are equal, or pathindex is even
-    // and nextindex is the consecutive odd number, index_xor will be 0,
-    // indicating that we don't have to update the path, but just
-    // compute the appropriate leaf given by the low bit of nextindex.
-    //
-    // Otherwise, say for example pathindex is 010010111 and nextindex
-    // is 010011000.  Then their XOR is 000001111, and stripping the low
-    // bit yields 000001110, so how_many_1_bits will be 3.
-    // That indicates (typically) that path[depth-3] was a left child,
-    // and now we need to change it to a right child by descending right
-    // from path[depth-4], and then filling the path after that with
-    // left children.
-    //
-    // When we wrap around, however, index_xor will be 111111110 (after
-    // we strip the low bit), and how_many_1_bits will be depth-1, but
-    // the new top child (of the root seed) we have to compute will be a
-    // left, not a right, child.
-    uint64_t index_xor = (nextindex ^ pathindex) & ~1;
-    nbits_t how_many_1_bits = __builtin_popcount(index_xor);
-    if (how_many_1_bits > 0) {
-        // This will almost always be 1, unless we've just wrapped
-        // around from the right subtree back to the left, in which case
-        // it will be 0.
-        bool top_changed_bit =
-            nextindex & (address_t(1) << how_many_1_bits);
-        path[depth-how_many_1_bits] =
-            rdpf.descend(path[depth-how_many_1_bits-1],
-                depth-how_many_1_bits-1, top_changed_bit, op_counter);
-        for (nbits_t i = depth-how_many_1_bits; i < depth-1; ++i) {
-            path[i+1] = rdpf.descend(path[i], i, 0, op_counter);
-        }
-    }
-    typename T::node leaf = rdpf.descend(path[depth-1], depth-1,
-        nextindex & 1, op_counter);
-    pathindex = nextindex;
-    nextindex = (nextindex + 1) & indexmask;
-    return leaf;
-}
-
 struct RDPF {
     // The type of nodes
     using node = DPFnode;
@@ -265,88 +181,6 @@ struct RDPF {
 
 };
 
-// I/O for RDPFs
-
-template <typename T>
-T& operator>>(T &is, RDPF &rdpf)
-{
-    is.read((char *)&rdpf.seed, sizeof(rdpf.seed));
-    uint8_t depth;
-    // The whichhalf bit is the high bit of depth
-    is.read((char *)&depth, sizeof(depth));
-    rdpf.whichhalf = !!(depth & 0x80);
-    depth &= 0x7f;
-    bool read_expanded = false;
-    if (depth > 64) {
-        read_expanded = true;
-        depth -= 64;
-    }
-    assert(depth <= ADDRESS_MAX_BITS);
-    rdpf.cw.clear();
-    for (uint8_t i=0; i<depth; ++i) {
-        DPFnode cw;
-        is.read((char *)&cw, sizeof(cw));
-        rdpf.cw.push_back(cw);
-    }
-    if (read_expanded) {
-        rdpf.expansion.resize(1<<depth);
-        is.read((char *)rdpf.expansion.data(),
-            sizeof(rdpf.expansion[0])<<depth);
-    }
-    value_t cfbits = 0;
-    is.read((char *)&cfbits, BITBYTES(depth));
-    rdpf.cfbits = cfbits;
-    is.read((char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
-    is.read((char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
-    is.read((char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
-
-    return is;
-}
-
-// Write the DPF to the output stream.  If expanded=true, then include
-// the expansion _if_ the DPF is itself already expanded.  You can use
-// this to write DPFs to files.
-template <typename T>
-T& write_maybe_expanded(T &os, const RDPF &rdpf,
-    bool expanded = true)
-{
-    os.write((const char *)&rdpf.seed, sizeof(rdpf.seed));
-    uint8_t depth = rdpf.cw.size();
-    assert(depth <= ADDRESS_MAX_BITS);
-    // The whichhalf bit is the high bit of depth
-    // If we're writing an expansion, add 64 to depth as well
-    uint8_t whichhalf_and_depth = depth |
-        (uint8_t(rdpf.whichhalf)<<7);
-    bool write_expansion = false;
-    if (expanded && rdpf.expansion.size() == (size_t(1)<<depth)) {
-        write_expansion = true;
-        whichhalf_and_depth += 64;
-    }
-    os.write((const char *)&whichhalf_and_depth,
-        sizeof(whichhalf_and_depth));
-    for (uint8_t i=0; i<depth; ++i) {
-        os.write((const char *)&rdpf.cw[i], sizeof(rdpf.cw[i]));
-    }
-    if (write_expansion) {
-        os.write((const char *)rdpf.expansion.data(),
-            sizeof(rdpf.expansion[0])<<depth);
-    }
-    os.write((const char *)&rdpf.cfbits, BITBYTES(depth));
-    os.write((const char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
-    os.write((const char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
-    os.write((const char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
-
-    return os;
-}
-
-// The ordinary << version never writes the expansion, since this is
-// what we use to send DPFs over the network.
-template <typename T>
-T& operator<<(T &os, const RDPF &rdpf)
-{
-    return write_maybe_expanded(os, rdpf, false);
-}
-
 // Computational peers will generate triples of RDPFs with the _same_
 // random target for use in Duoram.  They will each hold a share of the
 // target (neither knowing the complete target index).  They will each
@@ -396,34 +230,6 @@ struct RDPFTriple {
         bit_t whichchild, size_t &op_counter) const;
 };
 
-// I/O for RDPF Triples
-
-// We never write RDPFTriples over the network, so always write
-// the DPF expansions if they're available.
-template <typename T>
-T& operator<<(T &os, const RDPFTriple &rdpftrip)
-{
-    write_maybe_expanded(os, rdpftrip.dpf[0], true);
-    write_maybe_expanded(os, rdpftrip.dpf[1], true);
-    write_maybe_expanded(os, rdpftrip.dpf[2], true);
-    nbits_t depth = rdpftrip.dpf[0].depth();
-    os.write((const char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
-    os.write((const char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
-    return os;
-}
-
-template <typename T>
-T& operator>>(T &is, RDPFTriple &rdpftrip)
-{
-    is >> rdpftrip.dpf[0] >> rdpftrip.dpf[1] >> rdpftrip.dpf[2];
-    nbits_t depth = rdpftrip.dpf[0].depth();
-    rdpftrip.as_target.ashare = 0;
-    is.read((char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
-    rdpftrip.xs_target.xshare = 0;
-    is.read((char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
-    return is;
-}
-
 struct RDPFPair {
     // The type of node pairs
     using node = std::tuple<DPFnode, DPFnode>;
@@ -454,23 +260,6 @@ struct RDPFPair {
         bit_t whichchild, size_t &op_counter) const;
 };
 
-// I/O for RDPF Pairs
-
-// We never write RDPFPairs over the network, so always write
-// the DPF expansions if they're available.
-template <typename T>
-T& operator<<(T &os, const RDPFPair &rdpfpair)
-{
-    write_maybe_expanded(os, rdpfpair.dpf[0], true);
-    write_maybe_expanded(os, rdpfpair.dpf[1], true);
-    return os;
-}
-
-template <typename T>
-T& operator>>(T &is, RDPFPair &rdpfpair)
-{
-    is >> rdpfpair.dpf[0] >> rdpfpair.dpf[1];
-    return is;
-}
+#include "rdpf.tcc"
 
 #endif

+ 214 - 0
rdpf.tcc

@@ -0,0 +1,214 @@
+// Templated method implementations for rdpf.hpp
+
+// Create a StreamEval object that will start its output at index start.
+// It will wrap around to 0 when it hits 2^depth.  If use_expansion
+// is true, then if the DPF has been expanded, just output values
+// from that.  If use_expansion=false or if the DPF has not been
+// expanded, compute the values on the fly.
+template <typename T>
+StreamEval<T>::StreamEval(const T &rdpf, address_t start,
+    size_t &op_counter, bool use_expansion) : rdpf(rdpf),
+    op_counter(op_counter), use_expansion(use_expansion)
+{
+    depth = rdpf.depth();
+    // Prevent overflow of 1<<depth
+    if (depth < ADDRESS_MAX_BITS) {
+        indexmask = (address_t(1)<<depth)-1;
+    } else {
+        indexmask = ~0;
+    }
+    // Record that we haven't actually output the leaf for index start
+    // itself yet
+    nextindex = start;
+    if (use_expansion && rdpf.has_expansion()) {
+        // We just need to keep the counter, not compute anything
+        return;
+    }
+    path.resize(depth);
+    pathindex = start;
+    path[0] = rdpf.get_seed();
+    for (nbits_t i=1;i<depth;++i) {
+        bool dir = !!(pathindex & (address_t(1)<<(depth-i)));
+        path[i] = rdpf.descend(path[i-1], i-1, dir, op_counter);
+    }
+}
+
+template <typename T>
+typename T::node StreamEval<T>::next()
+{
+    if (use_expansion && rdpf.has_expansion()) {
+        // Just use the precomputed values
+        typename T::node leaf = rdpf.get_expansion(nextindex);
+        nextindex = (nextindex + 1) & indexmask;
+        return leaf;
+    }
+    // Invariant: in the first call to next(), nextindex = pathindex.
+    // Otherwise, nextindex = pathindex+1.
+    // Get the XOR of nextindex and pathindex, and strip the low bit.
+    // If nextindex and pathindex are equal, or pathindex is even
+    // and nextindex is the consecutive odd number, index_xor will be 0,
+    // indicating that we don't have to update the path, but just
+    // compute the appropriate leaf given by the low bit of nextindex.
+    //
+    // Otherwise, say for example pathindex is 010010111 and nextindex
+    // is 010011000.  Then their XOR is 000001111, and stripping the low
+    // bit yields 000001110, so how_many_1_bits will be 3.
+    // That indicates (typically) that path[depth-3] was a left child,
+    // and now we need to change it to a right child by descending right
+    // from path[depth-4], and then filling the path after that with
+    // left children.
+    //
+    // When we wrap around, however, index_xor will be 111111110 (after
+    // we strip the low bit), and how_many_1_bits will be depth-1, but
+    // the new top child (of the root seed) we have to compute will be a
+    // left, not a right, child.
+    uint64_t index_xor = (nextindex ^ pathindex) & ~1;
+    nbits_t how_many_1_bits = __builtin_popcount(index_xor);
+    if (how_many_1_bits > 0) {
+        // This will almost always be 1, unless we've just wrapped
+        // around from the right subtree back to the left, in which case
+        // it will be 0.
+        bool top_changed_bit =
+            nextindex & (address_t(1) << how_many_1_bits);
+        path[depth-how_many_1_bits] =
+            rdpf.descend(path[depth-how_many_1_bits-1],
+                depth-how_many_1_bits-1, top_changed_bit, op_counter);
+        for (nbits_t i = depth-how_many_1_bits; i < depth-1; ++i) {
+            path[i+1] = rdpf.descend(path[i], i, 0, op_counter);
+        }
+    }
+    typename T::node leaf = rdpf.descend(path[depth-1], depth-1,
+        nextindex & 1, op_counter);
+    pathindex = nextindex;
+    nextindex = (nextindex + 1) & indexmask;
+    return leaf;
+}
+
+// I/O for RDPFs
+
+template <typename T>
+T& operator>>(T &is, RDPF &rdpf)
+{
+    is.read((char *)&rdpf.seed, sizeof(rdpf.seed));
+    uint8_t depth;
+    // The whichhalf bit is the high bit of depth
+    is.read((char *)&depth, sizeof(depth));
+    rdpf.whichhalf = !!(depth & 0x80);
+    depth &= 0x7f;
+    bool read_expanded = false;
+    if (depth > 64) {
+        read_expanded = true;
+        depth -= 64;
+    }
+    assert(depth <= ADDRESS_MAX_BITS);
+    rdpf.cw.clear();
+    for (uint8_t i=0; i<depth; ++i) {
+        DPFnode cw;
+        is.read((char *)&cw, sizeof(cw));
+        rdpf.cw.push_back(cw);
+    }
+    if (read_expanded) {
+        rdpf.expansion.resize(1<<depth);
+        is.read((char *)rdpf.expansion.data(),
+            sizeof(rdpf.expansion[0])<<depth);
+    }
+    value_t cfbits = 0;
+    is.read((char *)&cfbits, BITBYTES(depth));
+    rdpf.cfbits = cfbits;
+    is.read((char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
+    is.read((char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
+    is.read((char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
+
+    return is;
+}
+
+// Write the DPF to the output stream.  If expanded=true, then include
+// the expansion _if_ the DPF is itself already expanded.  You can use
+// this to write DPFs to files.
+template <typename T>
+T& write_maybe_expanded(T &os, const RDPF &rdpf,
+    bool expanded = true)
+{
+    os.write((const char *)&rdpf.seed, sizeof(rdpf.seed));
+    uint8_t depth = rdpf.cw.size();
+    assert(depth <= ADDRESS_MAX_BITS);
+    // The whichhalf bit is the high bit of depth
+    // If we're writing an expansion, add 64 to depth as well
+    uint8_t whichhalf_and_depth = depth |
+        (uint8_t(rdpf.whichhalf)<<7);
+    bool write_expansion = false;
+    if (expanded && rdpf.expansion.size() == (size_t(1)<<depth)) {
+        write_expansion = true;
+        whichhalf_and_depth += 64;
+    }
+    os.write((const char *)&whichhalf_and_depth,
+        sizeof(whichhalf_and_depth));
+    for (uint8_t i=0; i<depth; ++i) {
+        os.write((const char *)&rdpf.cw[i], sizeof(rdpf.cw[i]));
+    }
+    if (write_expansion) {
+        os.write((const char *)rdpf.expansion.data(),
+            sizeof(rdpf.expansion[0])<<depth);
+    }
+    os.write((const char *)&rdpf.cfbits, BITBYTES(depth));
+    os.write((const char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
+    os.write((const char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
+    os.write((const char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
+
+    return os;
+}
+
+// The ordinary << version never writes the expansion, since this is
+// what we use to send DPFs over the network.
+template <typename T>
+T& operator<<(T &os, const RDPF &rdpf)
+{
+    return write_maybe_expanded(os, rdpf, false);
+}
+
+// I/O for RDPF Triples
+
+// We never write RDPFTriples over the network, so always write
+// the DPF expansions if they're available.
+template <typename T>
+T& operator<<(T &os, const RDPFTriple &rdpftrip)
+{
+    write_maybe_expanded(os, rdpftrip.dpf[0], true);
+    write_maybe_expanded(os, rdpftrip.dpf[1], true);
+    write_maybe_expanded(os, rdpftrip.dpf[2], true);
+    nbits_t depth = rdpftrip.dpf[0].depth();
+    os.write((const char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
+    os.write((const char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
+    return os;
+}
+
+template <typename T>
+T& operator>>(T &is, RDPFTriple &rdpftrip)
+{
+    is >> rdpftrip.dpf[0] >> rdpftrip.dpf[1] >> rdpftrip.dpf[2];
+    nbits_t depth = rdpftrip.dpf[0].depth();
+    rdpftrip.as_target.ashare = 0;
+    is.read((char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
+    rdpftrip.xs_target.xshare = 0;
+    is.read((char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
+    return is;
+}
+
+// I/O for RDPF Pairs
+
+// We never write RDPFPairs over the network, so always write
+// the DPF expansions if they're available.
+template <typename T>
+T& operator<<(T &os, const RDPFPair &rdpfpair)
+{
+    write_maybe_expanded(os, rdpfpair.dpf[0], true);
+    write_maybe_expanded(os, rdpfpair.dpf[1], true);
+    return os;
+}
+
+template <typename T>
+T& operator>>(T &is, RDPFPair &rdpfpair)
+{
+    is >> rdpfpair.dpf[0] >> rdpfpair.dpf[1];
+    return is;
+}