Browse Source

Start on the compare algorithm

Ian Goldberg 2 years ago
parent
commit
e07580ad9f
2 changed files with 65 additions and 0 deletions
  1. 50 0
      cdpf.cpp
  2. 15 0
      cdpf.hpp

+ 50 - 0
cdpf.cpp

@@ -152,3 +152,53 @@ DPFnode CDPF::leaf(value_t input, size_t &aes_ops) const
     node = descend_to_leaf(node, dir, aes_ops);
     return node;
 }
+
+// Compare the given additively shared element to 0.  The output is
+// a triple of bit shares; the first is a share of 1 iff the
+// reconstruction of the element is negative; the second iff it is
+// 0; the third iff it is positive.  (All as two's-complement
+// VALUE_BIT-bit integers.)  Note in particular that exactly one of
+// the outputs will be a share of 1, so you can do "greater than or
+// equal to" just by adding the greater and equal outputs together.
+// Note also that you can compare two RegAS values A and B by
+// passing A-B here.
+std::tuple<RegBS,RegBS,RegBS> CDPF::compare(MPCTIO &tio, yield_t &yield,
+    RegAS x)
+{
+    // Reconstruct S = target-x
+    RegBS gt, eq;
+    // The server does nothing in this protocol
+    if (tio.player() < 2) {
+        RegAS S_share = as_target - x;
+        tio.iostream_peer() << x;
+        yield();
+        RegAS peer_S_share;
+        tio.iostream_peer() >> peer_S_share;
+        value_t S = S_share.ashare + peer_S_share.ashare;
+
+        // Now we're going to simultaneously descend the DPF tree for
+        // the values S and T = S + 2^63.  Note that the 1 values of V
+        // (see the explanation of the algorithm in cdpf.hpp) are those
+        // values _strictly_ larger than S and smaller than T (noting
+        // they can "wrap around" 2^64).  In level 1 of the tree, the
+        // paths to S and T will necessarily be at the two different
+        // children of the root seed, but they could be in either order.
+        // From then on, they will proceed in lockstep, either both
+        // going left, or both going right.  If they both go left, we
+        // also compute the right sibling on the S path, and add it to
+        // the gt flag.  If they both go right, we also compute the left
+        // sibling on the T path, and add it to the gt flag.  When we
+        // hit the leaves, the gt flag will account for all of the
+        // complete leaf nodes strictly greater than S and strictly less
+        // than T.  Then we just have to pull out the parity of the
+        // appropriate bits in the two leaf nodes containing S and T
+        // respectively to complete the computation of gt, and also to
+        // get the single bit eq.
+    }
+    // Once we have gt and eq (which cannot both be 1), lt is just 1
+    // exactly if they're both 0.
+    RegBS lt;
+    lt.bshare = 1 ^ eq.bshare ^ gt.bshare;
+
+    return std::make_tuple(lt, eq, gt);
+}

+ 15 - 0
cdpf.hpp

@@ -2,6 +2,9 @@
 #define __CDPF_HPP__
 
 #include <tuple>
+
+#include "mpcio.hpp"
+#include "coroutine.hpp"
 #include "types.hpp"
 #include "dpf.hpp"
 
@@ -104,6 +107,18 @@ struct CDPF : public DPF {
     // Get the leaf node for the given input.  We don't actually use
     // this in the protocol, but it's useful for testing.
     DPFnode leaf(value_t input, size_t &aes_ops) const;
+
+    // Compare the given additively shared element to 0.  The output is
+    // a triple of bit shares; the first is a share of 1 iff the
+    // reconstruction of the element is negative; the second iff it is
+    // 0; the third iff it is positive.  (All as two's-complement
+    // VALUE_BIT-bit integers.)  Note in particular that exactly one of
+    // the outputs will be a share of 1, so you can do "greater than or
+    // equal to" just by adding the greater and equal outputs together.
+    // Note also that you can compare two RegAS values A and B by
+    // passing A-B here.
+    std::tuple<RegBS,RegBS,RegBS> compare(MPCTIO &tio, yield_t &yield,
+        RegAS x);
 };
 
 // Descend from the parent of a leaf node to the leaf node