| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 | #ifndef __DPF_HPP__#define __DPF_HPP__#include <vector>#include "prg.hpp"// We have two major kinds of distributed point functions (DPFs): ones// used for random-access memory (RDPFs) and ones used for comparisons// (CDPFs).  The major differences://// RDPFs are of depth r in order to obliviously access a memory of size// 2^r.  They are created jointly by P0 and P1, with O(r) communication,// but O(2^r) local computation.  They can output bit shares of a// single-bit unit vector, word-sized additive shares of a unit vector,// XOR shares of a scaled unit vector, or additive shares of a scaled// unit vector.  They are typically used by evaluating _all_ 2^r leaves.// All of the 2^r leaves have to be computed at creation time, anyway,// so you can choose to store an "expanded" version of them that just// records those precomputed values, making them much faster to use in// the online phase, at the cost of storage and memory (and the time it// takes to just read them from disk, particular on rotational media).//// CDPFs are only used to compare VALUE_BITS-bit values (typically// VALUE_BITS = 64), and can only output bit shares of a single-bit unit// vector. This allows for an optimization where the leaf nodes of the// DPF (which are 128 bits wide) can subsume the last 7 levels of the// tree, so the CDPF is actually of height VALUE_BITS-7 (typically 57).// They are never used to expand all leaves, since that's way too large,// nor could P0 and P1 jointly compute them in the way they compute// RDPFs. On the other hand, P2 never sees these CDPFs in the online// phase, so P2 can just create them and send the halves to P0 and P1 at// preprocessing time.  They are very cheap to create, store, and send// over the network (in the preprocessing phase), and evaluate (in the// online phase); all of these are O(VALUE_BITS-7), somewhat abusing O()// notation here.struct DPF {    // The type of nodes    using node = DPFnode;    // The 128-bit seed    DPFnode seed;    // Which half of the DPF are we?    bit_t whichhalf;    // correction words    std::vector<DPFnode> cw;    // correction flag bits: the one for level i is bit i of this word    value_t cfbits;    // The seed    inline node get_seed() const { return seed; }    // Descend from a node at depth parentdepth to one of its children    // whichchild = 0: left child    // whichchild = 1: right child    //    // Cost: 1 AES operation    inline DPFnode descend(const DPFnode &parent, nbits_t parentdepth,        bit_t whichchild, size_t &aes_ops) const;};// Descend from a node at depth parentdepth to one of its children// whichchild = 0: left child// whichchild = 1: right childinline DPFnode DPF::descend(const DPFnode &parent, nbits_t parentdepth,    bit_t whichchild, size_t &aes_ops) const{    DPFnode prgout;    bool flag = get_lsb(parent);    prg(prgout, parent, whichchild, aes_ops);    if (flag) {        DPFnode CW = cw[parentdepth];        bit_t cfbit = !!(cfbits & (value_t(1)<<parentdepth));        DPFnode CWR = CW ^ lsb128_mask[cfbit];        prgout ^= (whichchild ? CWR : CW);    }    return prgout;}// Don't warn if we never actually use these functionsstatic void dump_node(DPFnode node, const char *label = NULL)__attribute__ ((unused));static void dump_level(DPFnode *nodes, size_t num, const char *label = NULL)__attribute__ ((unused));static void dump_node(DPFnode node, const char *label){    if (label) printf("%s: ", label);    for(int i=0;i<16;++i) { printf("%02x", ((unsigned char *)&node)[15-i]); } printf("\n");}static void dump_level(DPFnode *nodes, size_t num, const char *label){    if (label) printf("%s:\n", label);    for (size_t i=0;i<num;++i) {        dump_node(nodes[i]);    }    printf("\n");}#endif
 |