| 
					
				 | 
			
			
				@@ -28,6 +28,8 @@ struct RDPF { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // XOR share of the scaling value M_xs such that the high words 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // of the leaf values for P0 and P1 XOR to M_xs * e_{target} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     RegXS scaled_xor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // If we're saving the expansion, put it here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::vector<DPFnode> expansion; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     RDPF() {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -44,7 +46,7 @@ struct RDPF { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // 2^{depth+1}-2 local AES operations for P0,P1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // 0 local AES operations for P2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     RDPF(MPCTIO &tio, yield_t &yield, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        RegXS target, nbits_t depth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        RegXS target, nbits_t depth, bool save_expansion = false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // The number of bytes it will take to store this RDPF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     size_t size() const; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -69,6 +71,9 @@ struct RDPF { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // Cost: depth AES operations 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     DPFnode leaf(address_t input, size_t &op_counter) const; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Expand the DPF if it's not already expanded 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    void expand(size_t &op_counter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // Get the bit-shared unit vector entry from the leaf node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     inline RegBS unit_bs(DPFnode leaf) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         RegBS b; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -121,6 +126,11 @@ T& operator>>(T &is, RDPF &rdpf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     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) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -128,6 +138,11 @@ T& operator>>(T &is, RDPF &rdpf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         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; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -138,20 +153,34 @@ T& operator>>(T &is, RDPF &rdpf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     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& operator<<(T &os, const RDPF &rdpf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -160,6 +189,14 @@ T& operator<<(T &os, const RDPF &rdpf) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     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 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -179,15 +216,19 @@ struct RDPFTriple { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // Construct three RDPFs of the given depth all with the same 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     // randomly generated target index. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     RDPFTriple(MPCTIO &tio, yield_t &yield, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        nbits_t depth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        nbits_t depth, bool save_expansion = 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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    os << rdpftrip.dpf[0] << rdpftrip.dpf[1] << rdpftrip.dpf[2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    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)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,10 +253,13 @@ struct RDPFPair { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    os << rdpfpair.dpf[0] << rdpfpair.dpf[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    write_maybe_expanded(os, rdpfpair.dpf[0], true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    write_maybe_expanded(os, rdpfpair.dpf[1], true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return os; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |