Quellcode durchsuchen

Creation of incremental RDPFs

Just in the online-only mode so far
Ian Goldberg vor 1 Jahr
Ursprung
Commit
bbcdd36b55
3 geänderte Dateien mit 198 neuen und 110 gelöschten Zeilen
  1. 95 63
      online.cpp
  2. 42 11
      rdpf.hpp
  3. 61 36
      rdpf.tcc

+ 95 - 63
online.cpp

@@ -208,7 +208,7 @@ static void lamport_test(MPCIO &mpcio,
 
 template <nbits_t WIDTH>
 static void rdpf_test(MPCIO &mpcio,
-    const PRACOptions &opts, char **args)
+    const PRACOptions &opts, char **args, bool incremental)
 {
     nbits_t depth=6;
     size_t num_iters = 1;
@@ -223,84 +223,101 @@ static void rdpf_test(MPCIO &mpcio,
     }
 
     MPCTIO tio(mpcio, 0, opts.num_threads);
-    run_coroutines(tio, [&tio, depth, num_iters] (yield_t &yield) {
+    run_coroutines(tio, [&tio, depth, num_iters, incremental] (yield_t &yield) {
         size_t &aes_ops = tio.aes_ops();
+        nbits_t min_level = incremental ? 1 : depth;
         for (size_t iter=0; iter < num_iters; ++iter) {
             if (tio.player() == 2) {
-                RDPFPair<WIDTH> dp = tio.rdpfpair<WIDTH>(yield, depth);
+                RDPFPair<WIDTH> dp = tio.rdpfpair<WIDTH>(yield, depth,
+                    incremental);
                 for (int i=0;i<2;++i) {
-                    const RDPF<WIDTH> &dpf = dp.dpf[i];
-                    for (address_t x=0;x<(address_t(1)<<depth);++x) {
-                        typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
-                        RegBS ub = dpf.unit_bs(leaf);
-                        RegAS ua = dpf.unit_as(leaf);
-                        typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
-                        typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
-                        printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
-                        for (nbits_t j=0;j<WIDTH;++j) {
-                            printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
+                    RDPF<WIDTH> &dpf = dp.dpf[i];
+                    for (nbits_t level=min_level; level<=depth; ++level) {
+                        if (incremental) {
+                            printf("Level = %u\n\n", level);
+                            dpf.depth(level);
+                        }
+                        for (address_t x=0;x<(address_t(1)<<level);++x) {
+                            typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
+                            RegBS ub = dpf.unit_bs(leaf);
+                            RegAS ua = dpf.unit_as(leaf);
+                            typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
+                            typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
+                            printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
+                            for (nbits_t j=0;j<WIDTH;++j) {
+                                printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
+                            }
+                            printf("\n");
                         }
                         printf("\n");
                     }
-                    printf("\n");
                 }
             } else {
-                RDPFTriple<WIDTH> dt = tio.rdpftriple<WIDTH>(yield, depth);
+                RDPFTriple<WIDTH> dt = tio.rdpftriple<WIDTH>(yield,
+                    depth, incremental);
                 for (int i=0;i<3;++i) {
-                    const RDPF<WIDTH> &dpf = dt.dpf[i];
-                    typename RDPF<WIDTH>::RegXSW peer_scaled_xor;
-                    typename RDPF<WIDTH>::RegASW peer_scaled_sum;
-                    if (tio.player() == 1) {
-                        tio.iostream_peer() << dpf.li[0].scaled_xor << dpf.li[0].scaled_sum;
-                    } else {
-                        tio.iostream_peer() >> peer_scaled_xor >> peer_scaled_sum;
-                        peer_scaled_sum += dpf.li[0].scaled_sum;
-                        peer_scaled_xor ^= dpf.li[0].scaled_xor;
-                    }
-                    for (address_t x=0;x<(address_t(1)<<depth);++x) {
-                        typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
-                        RegBS ub = dpf.unit_bs(leaf);
-                        RegAS ua = dpf.unit_as(leaf);
-                        typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
-                        typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
-                        printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
-                        for (nbits_t j=0;j<WIDTH;++j) {
-                            printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
+                    RDPF<WIDTH> &dpf = dt.dpf[i];
+                    for (nbits_t level=min_level; level<=depth; ++level) {
+                        if (incremental) {
+                            printf("Level = %u\n\n", level);
+                            dpf.depth(level);
                         }
-                        printf("\n");
+                        typename RDPF<WIDTH>::RegXSW peer_scaled_xor;
+                        typename RDPF<WIDTH>::RegASW peer_scaled_sum;
                         if (tio.player() == 1) {
-                            tio.iostream_peer() << ub << ua << sx << sa;
+                            tio.iostream_peer() <<
+                                dpf.li[depth-level].scaled_xor <<
+                                dpf.li[depth-level].scaled_sum;
                         } else {
-                            RegBS peer_ub;
-                            RegAS peer_ua;
-                            typename RDPF<WIDTH>::RegXSW peer_sx;
-                            typename RDPF<WIDTH>::RegASW peer_sa;
-                            tio.iostream_peer() >> peer_ub >> peer_ua >>
-                                peer_sx >> peer_sa;
-                            ub ^= peer_ub;
-                            ua += peer_ua;
-                            sx ^= peer_sx;
-                            sa += peer_sa;
-                            bool is_nonzero = ub.bshare || ua.ashare;
+                            tio.iostream_peer() >> peer_scaled_xor >> peer_scaled_sum;
+                            peer_scaled_sum += dpf.li[depth-level].scaled_sum;
+                            peer_scaled_xor ^= dpf.li[depth-level].scaled_xor;
+                        }
+                        for (address_t x=0;x<(address_t(1)<<level);++x) {
+                            typename RDPF<WIDTH>::LeafNode leaf = dpf.leaf(x, aes_ops);
+                            RegBS ub = dpf.unit_bs(leaf);
+                            RegAS ua = dpf.unit_as(leaf);
+                            typename RDPF<WIDTH>::RegXSW sx = dpf.scaled_xs(leaf);
+                            typename RDPF<WIDTH>::RegASW sa = dpf.scaled_as(leaf);
+                            printf("%04x %x %016lx", x, ub.bshare, ua.ashare);
                             for (nbits_t j=0;j<WIDTH;++j) {
-                                is_nonzero |= (sx[j].xshare || sa[j].ashare);
+                                printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
                             }
-                            if (is_nonzero) {
-                                printf("**** %x %016lx", ub.bshare, ua.ashare);
+                            printf("\n");
+                            if (tio.player() == 1) {
+                                tio.iostream_peer() << ub << ua << sx << sa;
+                            } else {
+                                RegBS peer_ub;
+                                RegAS peer_ua;
+                                typename RDPF<WIDTH>::RegXSW peer_sx;
+                                typename RDPF<WIDTH>::RegASW peer_sa;
+                                tio.iostream_peer() >> peer_ub >> peer_ua >>
+                                    peer_sx >> peer_sa;
+                                ub ^= peer_ub;
+                                ua += peer_ua;
+                                sx ^= peer_sx;
+                                sa += peer_sa;
+                                bool is_nonzero = ub.bshare || ua.ashare;
                                 for (nbits_t j=0;j<WIDTH;++j) {
-                                    printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
+                                    is_nonzero |= (sx[j].xshare || sa[j].ashare);
                                 }
-                                printf("\nSCALE                  ");
-                                for (nbits_t j=0;j<WIDTH;++j) {
-                                    printf(" %016lx %016lx",
-                                        peer_scaled_xor[j].xshare,
-                                        peer_scaled_sum[j].ashare);
+                                if (is_nonzero) {
+                                    printf("**** %x %016lx", ub.bshare, ua.ashare);
+                                    for (nbits_t j=0;j<WIDTH;++j) {
+                                        printf(" %016lx %016lx", sx[j].xshare, sa[j].ashare);
+                                    }
+                                    printf("\nSCALE                  ");
+                                    for (nbits_t j=0;j<WIDTH;++j) {
+                                        printf(" %016lx %016lx",
+                                            peer_scaled_xor[j].xshare,
+                                            peer_scaled_sum[j].ashare);
+                                    }
+                                    printf("\n");
                                 }
-                                printf("\n");
                             }
                         }
+                        printf("\n");
                     }
-                    printf("\n");
                 }
             }
         }
@@ -1190,19 +1207,34 @@ void online_main(MPCIO &mpcio, const PRACOptions &opts, char **args)
         lamport_test(mpcio, opts, args);
     } else if (!strcmp(*args, "rdpftest")) {
         ++args;
-        rdpf_test<1>(mpcio, opts, args);
+        rdpf_test<1>(mpcio, opts, args, false);
     } else if (!strcmp(*args, "rdpftest2")) {
         ++args;
-        rdpf_test<2>(mpcio, opts, args);
+        rdpf_test<2>(mpcio, opts, args, false);
     } else if (!strcmp(*args, "rdpftest3")) {
         ++args;
-        rdpf_test<3>(mpcio, opts, args);
+        rdpf_test<3>(mpcio, opts, args, false);
     } else if (!strcmp(*args, "rdpftest4")) {
         ++args;
-        rdpf_test<4>(mpcio, opts, args);
+        rdpf_test<4>(mpcio, opts, args, false);
     } else if (!strcmp(*args, "rdpftest5")) {
         ++args;
-        rdpf_test<5>(mpcio, opts, args);
+        rdpf_test<5>(mpcio, opts, args, false);
+    } else if (!strcmp(*args, "irdpftest")) {
+        ++args;
+        rdpf_test<1>(mpcio, opts, args, true);
+    } else if (!strcmp(*args, "irdpftest2")) {
+        ++args;
+        rdpf_test<2>(mpcio, opts, args, true);
+    } else if (!strcmp(*args, "irdpftest3")) {
+        ++args;
+        rdpf_test<3>(mpcio, opts, args, true);
+    } else if (!strcmp(*args, "irdpftest4")) {
+        ++args;
+        rdpf_test<4>(mpcio, opts, args, true);
+    } else if (!strcmp(*args, "irdpftest5")) {
+        ++args;
+        rdpf_test<5>(mpcio, opts, args, true);
     } else if (!strcmp(*args, "rdpftime")) {
         ++args;
         rdpf_timing(mpcio, opts, args);

+ 42 - 11
rdpf.hpp

@@ -103,16 +103,28 @@ struct RDPF : public DPF {
         bool save_expansion = false);
 
     // Do we have a precomputed expansion?
-    inline bool has_expansion() const { return li[0].expansion.size() > 0; }
+    inline bool has_expansion() const {
+        return li[maxdepth-curdepth].expansion.size() > 0;
+    }
 
     // Get an element of the expansion
     inline LeafNode get_expansion(address_t index) const {
-        return li[0].expansion[index];
+        return li[maxdepth-curdepth].expansion[index];
     }
 
     // The depth
     inline nbits_t depth() const { return curdepth; }
 
+    // Set the current depth for an incremental RDPF; 0 means to use
+    // maxdepth
+    inline void depth(nbits_t newdepth) {
+        if (newdepth > 0 && newdepth < maxdepth) {
+            curdepth = newdepth;
+        } else {
+            curdepth = maxdepth;
+        }
+    }
+
     // Get the leaf node for the given input
     //
     // Cost: depth AES operations
@@ -143,7 +155,7 @@ struct RDPF : public DPF {
         if (whichhalf == 1) {
             lowword = -lowword;
         }
-        a.ashare = lowword * li[0].unit_sum_inverse;
+        a.ashare = lowword * li[maxdepth-curdepth].unit_sum_inverse;
         return a;
     }
 
@@ -229,6 +241,14 @@ struct RDPFTriple {
     // The depth
     inline nbits_t depth() const { return dpf[0].depth(); }
 
+    // Set the current depth for an incremental RDPFTriple; 0 means to
+    // use maxdepth
+    inline void depth(nbits_t newdepth) {
+        dpf[0].depth(newdepth);
+        dpf[1].depth(newdepth);
+        dpf[2].depth(newdepth);
+    }
+
     // The seed
     inline node get_seed() const {
         return std::make_tuple(dpf[0].get_seed(), dpf[1].get_seed(),
@@ -237,7 +257,8 @@ struct RDPFTriple {
 
     // Do we have a precomputed expansion?
     inline bool has_expansion() const {
-        return dpf[0].li[0].expansion.size() > 0;
+        int li_index = dpf[0].maxdepth - dpf[0].curdepth;
+        return dpf[0].li[li_index].expansion.size() > 0;
     }
 
     // Get an element of the expansion
@@ -271,17 +292,19 @@ struct RDPFTriple {
     // Additive share of the scaling value M_as such that the high words
     // of the leaf values for P0 and P1 add to M_as * e_{target}
     inline void scaled_value(RegASWT &v) const {
-        std::get<0>(v) = dpf[0].li[0].scaled_sum;
-        std::get<1>(v) = dpf[1].li[0].scaled_sum;
-        std::get<2>(v) = dpf[2].li[0].scaled_sum;
+        int li_index = dpf[0].maxdepth - dpf[0].curdepth;
+        std::get<0>(v) = dpf[0].li[li_index].scaled_sum;
+        std::get<1>(v) = dpf[1].li[li_index].scaled_sum;
+        std::get<2>(v) = dpf[2].li[li_index].scaled_sum;
     }
 
     // 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}
     inline void scaled_value(RegXSWT &v) const {
-        std::get<0>(v) = dpf[0].li[0].scaled_xor;
-        std::get<1>(v) = dpf[1].li[0].scaled_xor;
-        std::get<2>(v) = dpf[2].li[0].scaled_xor;
+        int li_index = dpf[0].maxdepth - dpf[0].curdepth;
+        std::get<0>(v) = dpf[0].li[li_index].scaled_xor;
+        std::get<1>(v) = dpf[1].li[li_index].scaled_xor;
+        std::get<2>(v) = dpf[2].li[li_index].scaled_xor;
     }
 
     // Get the additive-shared unit vector entry from the leaf node
@@ -354,6 +377,13 @@ struct RDPFPair {
     // The depth
     inline nbits_t depth() const { return dpf[0].depth(); }
 
+    // Set the current depth for an incremental RDPFPair; 0 means to use
+    // maxdepth
+    inline void depth(nbits_t newdepth) {
+        dpf[0].depth(newdepth);
+        dpf[1].depth(newdepth);
+    }
+
     // The seed
     inline node get_seed() const {
         return std::make_tuple(dpf[0].get_seed(), dpf[1].get_seed());
@@ -361,7 +391,8 @@ struct RDPFPair {
 
     // Do we have a precomputed expansion?
     inline bool has_expansion() const {
-        return dpf[0].li[0].expansion.size() > 0;
+        int li_index = dpf[0].maxdepth - dpf[0].curdepth;
+        return dpf[0].li[li_index].expansion.size() > 0;
     }
 
     // Get an element of the expansion

+ 61 - 36
rdpf.tcc

@@ -193,7 +193,7 @@ inline typename RDPF<WIDTH>::LeafNode RDPF<WIDTH>::descend_to_leaf(
     bool flag = get_lsb(parent);
     prg(prgout, parent, whichchild, aes_ops);
     if (flag) {
-        LeafNode CW = li[0].leaf_cw;
+        LeafNode CW = li[maxdepth-parentdepth-1].leaf_cw;
         LeafNode CWR = CW;
         bit_t cfbit = !!(leaf_cfbits &
             (value_t(1)<<(maxdepth-parentdepth-1)));
@@ -211,9 +211,15 @@ T& operator>>(T &is, RDPF<WIDTH> &rdpf)
     is.read((char *)&rdpf.seed, sizeof(rdpf.seed));
     rdpf.whichhalf = get_lsb(rdpf.seed);
     uint8_t depth;
-    // Add 64 to depth to indicate an expanded RDPF
+    // Add 64 to depth to indicate an expanded RDPF, and add 128 to
+    // indicate an incremental RDPF
     is.read((char *)&depth, sizeof(depth));
     bool read_expanded = false;
+    bool read_incremental = false;
+    if (depth > 128) {
+        read_incremental = true;
+        depth -= 128;
+    }
     if (depth > 64) {
         read_expanded = true;
         depth -= 64;
@@ -227,19 +233,22 @@ T& operator>>(T &is, RDPF<WIDTH> &rdpf)
         is.read((char *)&cw, sizeof(cw));
         rdpf.cw.push_back(cw);
     }
+    nbits_t num_leaflevels = read_incremental ? depth : 1;
+    rdpf.li.resize(num_leaflevels);
     if (read_expanded) {
-        rdpf.li[0].expansion.resize(1<<depth);
-        is.read((char *)rdpf.li[0].expansion.data(),
-            sizeof(rdpf.li[0].expansion[0])<<depth);
+        for(nbits_t i=0; i<num_leaflevels; ++i) {
+            nbits_t level = depth-i;
+            rdpf.li[i].expansion.resize(1<<level);
+            is.read((char *)rdpf.li[i].expansion.data(),
+                sizeof(rdpf.li[i].expansion[0])<<level);
+        }
     }
     value_t cfbits = 0;
     is.read((char *)&cfbits, BITBYTES(depth-1));
     rdpf.cfbits = cfbits;
-    nbits_t num_leaflevels = 1;
     value_t leaf_cfbits = 0;
     is.read((char *)&leaf_cfbits, BITBYTES(num_leaflevels));
     rdpf.leaf_cfbits = leaf_cfbits;
-    rdpf.li.resize(num_leaflevels);
     for (nbits_t i=0; i<num_leaflevels; ++i) {
         is.read((char *)&rdpf.li[i].leaf_cw,
             sizeof(rdpf.li[i].leaf_cw));
@@ -271,16 +280,23 @@ T& write_maybe_expanded(T &os, const RDPF<WIDTH> &rdpf,
         write_expansion = true;
         expanded_depth += 64;
     }
+    // If we're writing an incremental RDPF, add 128 to depth
+    if (rdpf.li.size() > 1) {
+        expanded_depth += 128;
+    }
     os.write((const char *)&expanded_depth, sizeof(expanded_depth));
     for (uint8_t i=0; i<depth-1; ++i) {
         os.write((const char *)&rdpf.cw[i], sizeof(rdpf.cw[i]));
     }
+    nbits_t num_leaflevels = rdpf.li.size();
     if (write_expansion) {
-        os.write((const char *)rdpf.li[0].expansion.data(),
-            sizeof(rdpf.li[0].expansion[0])<<depth);
+        for(nbits_t i=0; i<num_leaflevels; ++i) {
+            nbits_t level = depth-i;
+            os.write((const char *)rdpf.li[i].expansion.data(),
+                sizeof(rdpf.li[i].expansion[0])<<level);
+        }
     }
     os.write((const char *)&rdpf.cfbits, BITBYTES(depth-1));
-    nbits_t num_leaflevels = 1;
     os.write((const char *)&rdpf.leaf_cfbits, BITBYTES(num_leaflevels));
     for (nbits_t i=0; i<num_leaflevels; ++i) {
         os.write((const char *)&rdpf.li[i].leaf_cw,
@@ -802,7 +818,7 @@ static inline void create_level(MPCTIO &tio, yield_t &yield,
             assert(low_sum & 1);
             li.unit_sum_inverse = inverse_value_t(low_sum);
         }
-    } else if (level == depth-1) {
+    } else if constexpr (!std::is_same_v<NT, DPFnode>) {
         yield();
     }
 }
@@ -839,7 +855,7 @@ RDPF<WIDTH>::RDPF(MPCTIO &tio, yield_t &yield,
     DPFnode *nextlevel = new DPFnode[1];
     nextlevel[0] = seed;
 
-    li.resize(1);
+    li.resize(incremental ? depth : 1);
 
     // Construct each intermediate level
     while(level < depth) {
@@ -848,20 +864,21 @@ RDPF<WIDTH>::RDPF(MPCTIO &tio, yield_t &yield,
             delete[] curlevel;
             curlevel = nextlevel;
             nextlevel = NULL;
-            if (save_expansion && level == depth-1) {
-                li[0].expansion.resize(1<<depth);
-                leaflevel = li[0].expansion.data();
-            } else if (level == depth-1) {
-                leaflevel = new LeafNode[1<<depth];
-            } else {
+            if (save_expansion && (incremental || level == depth-1)) {
+                li[depth-1-level].expansion.resize(1<<(level+1));
+                leaflevel = li[depth-1-level].expansion.data();
+            } else if (incremental || level == depth-1) {
+                leaflevel = new LeafNode[1<<(level+1)];
+            }
+            if (level < depth-1) {
                 nextlevel = new DPFnode[1<<(level+1)];
             }
         }
-        // Invariant: curlevel has 2^level elements; nextlevel has
-        // 2^{level+1} DPFnode elements if we're not at the last level,
-        // and leaflevel has 2^{level+1} LeafNode elements if we are at
-        // a leaf level (the last level always, and all levels if we are
-        // making an incremental RDPF).
+        // Invariant: curlevel has 2^level DPFnode elements; nextlevel
+        // has 2^{level+1} DPFnode elements if we're not at the last
+        // level, and leaflevel has 2^{level+1} LeafNode elements if we
+        // are at a leaf level (the last level always, and all levels if
+        // we are making an incremental RDPF).
 
         // The bit-shared choice bit is bit (depth-level-1) of the
         // XOR-shared target index
@@ -870,20 +887,24 @@ RDPF<WIDTH>::RDPF(MPCTIO &tio, yield_t &yield,
 
         if (level < depth-1) {
             DPFnode CW;
+            // This field is ignored when we're not expanding to a leaf
+            // level, but it needs to be an lvalue reference.
+            int noleafinfo = 0;
             create_level(tio, yield, curlevel, nextlevel, player, level,
-                depth, bs_choice, CW, cfbit, save_expansion, li[0],
+                depth, bs_choice, CW, cfbit, save_expansion, noleafinfo,
                 aes_ops);
             cfbits |= (value_t(cfbit)<<level);
             if (player < 2) {
                 cw.push_back(CW);
             }
-        } else {
+        }
+        if (incremental || level == depth-1) {
             LeafNode CW;
             create_level(tio, yield, curlevel, leaflevel, player, level,
-                depth, bs_choice, CW, cfbit, save_expansion, li[0],
-                aes_ops);
+                depth, bs_choice, CW, cfbit, save_expansion,
+                li[depth-level-1], aes_ops);
             leaf_cfbits |= (value_t(cfbit)<<(depth-level-1));
-            li[0].leaf_cw = CW;
+            li[depth-level-1].leaf_cw = CW;
         }
 
         if (!save_expansion) {
@@ -902,8 +923,8 @@ typename RDPF<WIDTH>::LeafNode
     RDPF<WIDTH>::leaf(address_t input, size_t &aes_ops) const
 {
     // If we have a precomputed expansion, just use it
-    if (li[0].expansion.size()) {
-        return li[0].expansion[input];
+    if (li[maxdepth-curdepth].expansion.size()) {
+        return li[maxdepth-curdepth].expansion[input];
     }
 
     DPFnode node = seed;
@@ -924,8 +945,8 @@ void RDPF<WIDTH>::expand(size_t &aes_ops)
 {
     nbits_t depth = this->depth();
     size_t num_leaves = size_t(1)<<depth;
-    if (li[0].expansion.size() == num_leaves) return;
-    li[0].expansion.resize(num_leaves);
+    if (li[maxdepth-depth].expansion.size() == num_leaves) return;
+    li[maxdepth-depth].expansion.resize(num_leaves);
     address_t index = 0;
     address_t lastindex = 0;
     DPFnode *path = new DPFnode[depth];
@@ -933,8 +954,10 @@ void RDPF<WIDTH>::expand(size_t &aes_ops)
     for (nbits_t i=1;i<depth;++i) {
         path[i] = descend(path[i-1], i-1, 0, aes_ops);
     }
-    li[0].expansion[index++] = descend_to_leaf(path[depth-1], depth-1, 0, aes_ops);
-    li[0].expansion[index++] = descend_to_leaf(path[depth-1], depth-1, 1, aes_ops);
+    li[maxdepth-depth].expansion[index++] =
+        descend_to_leaf(path[depth-1], depth-1, 0, aes_ops);
+    li[maxdepth-depth].expansion[index++] =
+        descend_to_leaf(path[depth-1], depth-1, 1, aes_ops);
     while(index < num_leaves) {
         // Invariant: lastindex and index will both be even, and
         // index=lastindex+2
@@ -954,8 +977,10 @@ void RDPF<WIDTH>::expand(size_t &aes_ops)
             path[i+1] = descend(path[i], i, 0, aes_ops);
         }
         lastindex = index;
-        li[0].expansion[index++] = descend_to_leaf(path[depth-1], depth-1, 0, aes_ops);
-        li[0].expansion[index++] = descend_to_leaf(path[depth-1], depth-1, 1, aes_ops);
+        li[maxdepth-depth].expansion[index++] =
+            descend_to_leaf(path[depth-1], depth-1, 0, aes_ops);
+        li[maxdepth-depth].expansion[index++] =
+            descend_to_leaf(path[depth-1], depth-1, 1, aes_ops);
     }
 
     delete[] path;