cdpf.hpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #ifndef __CDPF_HPP__
  2. #define __CDPF_HPP__
  3. #include <tuple>
  4. #include "mpcio.hpp"
  5. #include "coroutine.hpp"
  6. #include "types.hpp"
  7. #include "dpf.hpp"
  8. // DPFs for doing comparisons of (typically) 64-bit values. We use the
  9. // technique from:
  10. //
  11. // Kyle Storrier, Adithya Vadapalli, Allan Lyons, Ryan Henry.
  12. // Grotto: Screaming fast (2 + 1)-PC for Z_{2^n} via (2, 2)-DPFs
  13. //
  14. // The idea is that we have a pair of DPFs with 64-bit inputs and a
  15. // single-bit output. The outputs of these DPFs are the same for all
  16. // 64-bit inputs x except for one special one (target), where they're
  17. // different, but if you have just one of the DPFs, you can't tell what
  18. // the value of target is. The construction of the DPF is a binary
  19. // tree, where each interior node has a 128-bit value, the low bit of
  20. // which is the "flag" bit. The invariant is that if a node is on the
  21. // path leading to the target, then not only are the two 128-bit values
  22. // on the node (one from each DPF) different, but their flag (low) bits
  23. // are themselves different, and if a node is not on the path leading to
  24. // the target, then its 128-bit value is the _same_ in the two DPFs.
  25. // Each DPF also comes with an additive share (target0 or target1) of
  26. // the random target value.
  27. //
  28. // Given additive shares x0 and x1 of x, two parties can determine
  29. // bitwise shares of whether x>0 as follows: exchange (target0-x0) and
  30. // (target1-x1); both sides add them to produce S = (target-x).
  31. // Notionally consider (but do not actually construct) a bit vector V of
  32. // length 2^64 with 1s at positions S+1, S+2, ..., S+(2^63-1), wrapping
  33. // around if the indices exceed 2^64-1. Now consider (but again do not
  34. // actually do) the dot product of V with the full evaluation of the
  35. // DPFs. The full evaluations of the DPFs are random bit vectors that
  36. // differ in only the bit at position target, so the two dot products
  37. // (which are each a single bit) will be a bitwise shraring of the value
  38. // of V at position target. Note that if V[target] = 1, then target =
  39. // S+k for some 1 <= k <= 2^63-1, then since target = S+x, we have that
  40. // x = k is in that same range; i.e. x>0 as a 64-bit signed integer (and
  41. // similarly if V[target] = 0, then x <= 0.
  42. //
  43. // So far, this is all standard, and for DPFs of smaller depth, this is
  44. // the same technique we're doing for RDPFs. But we can't do it for
  45. // vectors of size 2^64; that's too big. Even for 2^32 it would be
  46. // annoying. The observation made in the Grotto paper is that you can
  47. // actually compute this bit sharing in time linear in the *depth* of
  48. // the DPF (that is, logarithmic in the length of V), for some kinds of
  49. // vectors V, including the "single block of 1s" one described above.
  50. //
  51. // The key insight is that if you look at any _interior_ node of the
  52. // tree, the corresponding nodes on the two DPFs will be a bit sharing
  53. // of the sum of all the leaves in the subtree rooted at that interior
  54. // node: 0 if target is not in that subtree, and 1 if it is. So you
  55. // just have to find the minimal set of interior nodes such that the
  56. // leaves of the subtrees rooted at those nodes is exactly the block of
  57. // 1s in V, and then each party adds up the flag bits of those leaves.
  58. // The result is a bit sharing of 1 if V[target]=1 and 0 if V[target]=0;
  59. // that is, it is a bit sharing of V[target], and so (as above) of the
  60. // result of the comparison [x>0]. You can also find and evaluate the
  61. // flag bits of this minimal set in time and memory linear in the depth
  62. // of the DPF.
  63. //
  64. // So at the end, we've computed a bit sharing of [x>0] with local
  65. // computation linear in the depth of the DPF (concretely, 170 AES
  66. // operations), and only a *single word* of communication in each
  67. // direction (exchanging the target{i}-x{i} values). Of course, this
  68. // assumes you have one pair of these DPFs lying around, and you have to
  69. // use a fresh pair with a fresh random target value for each
  70. // comparison, since revealing target-x for two different x's but the
  71. // same target leaks the difference of the x's. But in the 3-party
  72. // setting (or even the 2+1-party setting), you can just have the server
  73. // at preprocessing time precompute a bunch of these pairs in advance,
  74. // and hand bunches of the first item in each pair to player 0 and the
  75. // second item in each pair to player 1 (a single message from the
  76. // server to each of player 0 and player 1). These DPFs are very fast to
  77. // compute, and very small (< 1KB each) to transmit and store.
  78. // See also dpf.hpp for the differences between these DPFs and the ones
  79. // we use for oblivious random access to memory.
  80. struct CDPF : public DPF {
  81. // Additive and XOR shares of the target value
  82. RegAS as_target;
  83. RegXS xs_target;
  84. // The extra correction word we'll need for the right child at the
  85. // final leaf layer; this is needed because we're making the tree 7
  86. // layers shorter than you would naively expect (depth 57 instead of
  87. // 64), and having the 128-bit labels on the leaf nodes directly
  88. // represent the 128 bits that would have come out of the subtree of
  89. // a (notional) depth-64 tree rooted at that depth-57 node.
  90. DPFnode leaf_cwr;
  91. // Generate a pair of CDPFs with the given target value
  92. //
  93. // Cost:
  94. // 4*VALUE_BITS - 28 = 228 local AES operations
  95. static std::tuple<CDPF,CDPF> generate(value_t target, size_t &aes_ops);
  96. // Generate a pair of CDPFs with a random target value
  97. //
  98. // Cost:
  99. // 4*VALUE_BITS - 28 = 228 local AES operations
  100. static std::tuple<CDPF,CDPF> generate(size_t &aes_ops);
  101. // Descend from the parent of a leaf node to the leaf node
  102. inline DPFnode descend_to_leaf(const DPFnode &parent,
  103. bit_t whichchild, size_t &aes_ops) const;
  104. // Get the leaf node for the given input. We don't actually use
  105. // this in the protocol, but it's useful for testing.
  106. DPFnode leaf(value_t input, size_t &aes_ops) const;
  107. // Compare the given additively shared element to 0. The output is
  108. // a triple of bit shares; the first is a share of 1 iff the
  109. // reconstruction of the element is negative; the second iff it is
  110. // 0; the third iff it is positive. (All as two's-complement
  111. // VALUE_BIT-bit integers.) Note in particular that exactly one of
  112. // the outputs will be a share of 1, so you can do "greater than or
  113. // equal to" just by adding the greater and equal outputs together.
  114. // Note also that you can compare two RegAS values A and B by
  115. // passing A-B here.
  116. //
  117. // Cost:
  118. // 1 word sent in 1 message
  119. // 3*VALUE_BITS - 22 = 170 local AES operations
  120. std::tuple<RegBS,RegBS,RegBS> compare(MPCTIO &tio, yield_t &yield,
  121. RegAS x, size_t &aes_ops);
  122. // You can call this version directly if you already have S = target-x
  123. // reconstructed. This routine is entirely local; no communication
  124. // is needed.
  125. //
  126. // Cost:
  127. // 3*VALUE_BITS - 22 = 170 local AES operations
  128. std::tuple<RegBS,RegBS,RegBS> compare(value_t S, size_t &aes_ops);
  129. };
  130. // Descend from the parent of a leaf node to the leaf node
  131. inline DPFnode CDPF::descend_to_leaf(const DPFnode &parent,
  132. bit_t whichchild, size_t &aes_ops) const
  133. {
  134. DPFnode prgout;
  135. bool flag = get_lsb(parent);
  136. prg(prgout, parent, whichchild, aes_ops);
  137. if (flag) {
  138. DPFnode CW = cw.back();
  139. DPFnode CWR = leaf_cwr;
  140. prgout ^= (whichchild ? CWR : CW);
  141. }
  142. return prgout;
  143. }
  144. #include "cdpf.tcc"
  145. #endif