rdpf.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #ifndef __RDPF_HPP__
  2. #define __RDPF_HPP__
  3. #include <vector>
  4. #include <iostream>
  5. #include "mpcio.hpp"
  6. #include "coroutine.hpp"
  7. #include "types.hpp"
  8. #include "bitutils.hpp"
  9. struct RDPF {
  10. // The 128-bit seed
  11. DPFnode seed;
  12. // Which half of the DPF are we?
  13. bit_t whichhalf;
  14. // correction words; the depth of the DPF is the length of this
  15. // vector
  16. std::vector<DPFnode> cw;
  17. // correction flag bits: the one for level i is bit i of this word
  18. value_t cfbits;
  19. // The amount we have to scale the low words of the leaf values by
  20. // to get additive shares of a unit vector
  21. value_t unit_sum_inverse;
  22. // Additive share of the scaling value M_as such that the high words
  23. // of the leaf values for P0 and P1 add to M_as * e_{target}
  24. RegAS scaled_sum;
  25. // XOR share of the scaling value M_xs such that the high words
  26. // of the leaf values for P0 and P1 XOR to M_xs * e_{target}
  27. RegXS scaled_xor;
  28. RDPF() {}
  29. // Construct a DPF with the given (XOR-shared) target location, and
  30. // of the given depth, to be used for random-access memory reads and
  31. // writes. The DPF is constructed collaboratively by P0 and P1,
  32. // with the server P2 helping by providing correlated randomness,
  33. // such as SelectTriples.
  34. //
  35. // Cost:
  36. // (2 DPFnode + 2 bytes)*depth + 1 word communication in
  37. // 2*depth + 1 messages
  38. // (2 DPFnode + 1 byte)*depth communication from P2 to each party
  39. // 2^{depth+1}-2 local AES operations for P0,P1
  40. // 0 local AES operations for P2
  41. RDPF(MPCTIO &tio, yield_t &yield,
  42. RegXS target, nbits_t depth);
  43. // The number of bytes it will take to store this RDPF
  44. size_t size() const;
  45. // The number of bytes it will take to store a RDPF of the given
  46. // depth
  47. static size_t size(nbits_t depth);
  48. // The depth
  49. inline nbits_t depth() const { return cw.size(); }
  50. // Descend from a node at depth parentdepth to one of its children
  51. // whichchild = 0: left child
  52. // whichchild = 1: right child
  53. //
  54. // Cost: 1 AES operation
  55. DPFnode descend(const DPFnode parent, nbits_t parentdepth,
  56. bit_t whichchild, size_t &op_counter) const;
  57. // Get the leaf node for the given input
  58. //
  59. // Cost: depth AES operations
  60. DPFnode leaf(address_t input, size_t &op_counter) const;
  61. // Get the bit-shared unit vector entry from the leaf node
  62. inline RegBS unit_bs(DPFnode leaf) const {
  63. RegBS b;
  64. b.bshare = get_lsb(leaf);
  65. return b;
  66. }
  67. // Get the additive-shared unit vector entry from the leaf node
  68. inline RegAS unit_as(DPFnode leaf) const {
  69. RegAS a;
  70. value_t lowword = value_t(_mm_cvtsi128_si64x(leaf));
  71. if (whichhalf == 1) {
  72. lowword = -lowword;
  73. }
  74. a.ashare = lowword * unit_sum_inverse;
  75. return a;
  76. }
  77. // Get the XOR-shared scaled vector entry from the leaf ndoe
  78. inline RegXS scaled_xs(DPFnode leaf) const {
  79. RegXS x;
  80. value_t highword =
  81. value_t(_mm_cvtsi128_si64x(_mm_srli_si128(leaf,8)));
  82. x.xshare = highword;
  83. return x;
  84. }
  85. // Get the additive-shared scaled vector entry from the leaf ndoe
  86. inline RegAS scaled_as(DPFnode leaf) const {
  87. RegAS a;
  88. value_t highword =
  89. value_t(_mm_cvtsi128_si64x(_mm_srli_si128(leaf,8)));
  90. if (whichhalf == 1) {
  91. highword = -highword;
  92. }
  93. a.ashare = highword;
  94. return a;
  95. }
  96. };
  97. // I/O for RDPFs
  98. template <typename T>
  99. T& operator>>(T &is, RDPF &rdpf)
  100. {
  101. is.read((char *)&rdpf.seed, sizeof(rdpf.seed));
  102. uint8_t depth;
  103. // The whichhalf bit is the high bit of depth
  104. is.read((char *)&depth, sizeof(depth));
  105. rdpf.whichhalf = !!(depth & 0x80);
  106. depth &= 0x7f;
  107. assert(depth <= ADDRESS_MAX_BITS);
  108. rdpf.cw.clear();
  109. for (uint8_t i=0; i<depth; ++i) {
  110. DPFnode cw;
  111. is.read((char *)&cw, sizeof(cw));
  112. rdpf.cw.push_back(cw);
  113. }
  114. value_t cfbits = 0;
  115. is.read((char *)&cfbits, BITBYTES(depth));
  116. rdpf.cfbits = cfbits;
  117. is.read((char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
  118. is.read((char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
  119. is.read((char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
  120. return is;
  121. }
  122. template <typename T>
  123. T& operator<<(T &os, const RDPF &rdpf)
  124. {
  125. os.write((const char *)&rdpf.seed, sizeof(rdpf.seed));
  126. uint8_t depth = rdpf.cw.size();
  127. assert(depth <= ADDRESS_MAX_BITS);
  128. // The whichhalf bit is the high bit of depth
  129. uint8_t whichhalf_and_depth = depth |
  130. (uint8_t(rdpf.whichhalf)<<7);
  131. os.write((const char *)&whichhalf_and_depth,
  132. sizeof(whichhalf_and_depth));
  133. for (uint8_t i=0; i<depth; ++i) {
  134. os.write((const char *)&rdpf.cw[i], sizeof(rdpf.cw[i]));
  135. }
  136. os.write((const char *)&rdpf.cfbits, BITBYTES(depth));
  137. os.write((const char *)&rdpf.unit_sum_inverse, sizeof(rdpf.unit_sum_inverse));
  138. os.write((const char *)&rdpf.scaled_sum, sizeof(rdpf.scaled_sum));
  139. os.write((const char *)&rdpf.scaled_xor, sizeof(rdpf.scaled_xor));
  140. return os;
  141. }
  142. // Computational peers will generate triples of RDPFs with the _same_
  143. // random target for use in Duoram. They will each hold a share of the
  144. // target (neither knowing the complete target index). They will each
  145. // give one of the DPFs (not a matching pair) to the server, but not the
  146. // shares of the target index. So computational peers will hold a
  147. // RDPFTriple (which includes both an additive and an XOR share of the
  148. // target index), while the server will hold a RDPFPair (which does
  149. // not).
  150. struct RDPFTriple {
  151. RegAS as_target;
  152. RegXS xs_target;
  153. RDPF dpf[3];
  154. RDPFTriple() {}
  155. // Construct three RDPFs of the given depth all with the same
  156. // randomly generated target index.
  157. RDPFTriple(MPCTIO &tio, yield_t &yield,
  158. nbits_t depth);
  159. };
  160. // I/O for RDPF Triples
  161. template <typename T>
  162. T& operator<<(T &os, const RDPFTriple &rdpftrip)
  163. {
  164. os << rdpftrip.dpf[0] << rdpftrip.dpf[1] << rdpftrip.dpf[2];
  165. nbits_t depth = rdpftrip.dpf[0].depth();
  166. os.write((const char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
  167. os.write((const char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
  168. return os;
  169. }
  170. template <typename T>
  171. T& operator>>(T &is, RDPFTriple &rdpftrip)
  172. {
  173. is >> rdpftrip.dpf[0] >> rdpftrip.dpf[1] >> rdpftrip.dpf[2];
  174. nbits_t depth = rdpftrip.dpf[0].depth();
  175. rdpftrip.as_target.ashare = 0;
  176. is.read((char *)&rdpftrip.as_target.ashare, BITBYTES(depth));
  177. rdpftrip.xs_target.xshare = 0;
  178. is.read((char *)&rdpftrip.xs_target.xshare, BITBYTES(depth));
  179. return is;
  180. }
  181. struct RDPFPair {
  182. RDPF dpf[2];
  183. };
  184. // I/O for RDPF Pairs
  185. template <typename T>
  186. T& operator<<(T &os, const RDPFPair &rdpfpair)
  187. {
  188. os << rdpfpair.dpf[0] << rdpfpair.dpf[1];
  189. return os;
  190. }
  191. template <typename T>
  192. T& operator>>(T &is, RDPFPair &rdpfpair)
  193. {
  194. is >> rdpfpair.dpf[0] >> rdpfpair.dpf[1];
  195. return is;
  196. }
  197. #endif