Checkpoint the party/runtime stack before share-program and malicious-mode work.

Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-28 05:59:19 -06:00
parent 695f8e84f7
commit 0d22946a0e
1835 changed files with 170291 additions and 2849 deletions

View file

@ -11,9 +11,10 @@
/// cancels.
///
/// Default calls take XOR shares of the point. Tagged with
/// `arith_input`, the point is the ring sum of the two shares; path
/// bits are opened by a carry chain inside the local CW protocol so
/// the words match `make_dpf(x0 + x1)` at the caller's query.
/// `arith_input`, the point is the ring sum of the two shares. A
/// beaver ripple-carry converts those shares to XOR shares of the
/// sum bits before the walk, so the words match `make_dpf` on that
/// sum. The sum is not opened.
///
/// `geneval_cmp` is the comparison-channel form. The value-correction
/// word is a function of the secret path at every level, so the walk
@ -21,6 +22,7 @@
/// Doerner–Shelat comparison key. Prefix shares are
/// `eval_point(cmp, ...)` at each endpoint. Piecewise-cubic evaluation
/// on top of that is `grotto::geneval_offset_horner`.
/// @note The per-level correction opening follows Jack Doerner and abhi shelat, CCS 2017 (ePrint 2017/827). They return a reusable key. This function opens a word only for nodes on the public query trie and, with a local pad tape, sends nothing.
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
/// see [LICENSE.md](@ref license) for details.
@ -46,6 +48,7 @@
#include "dpf/doerner_shelat.hpp"
#include "dpf/eval_target.hpp"
#include "dpf/leaf_node.hpp"
#include "dpf/verifiable.hpp"
namespace dpf
{
@ -69,6 +72,9 @@ struct geneval_result
std::size_t live_levels = 0;
bool leaf_live = false;
Leaf leaf{};
/// @brief Party 0 / 1 VDPF tokens over the live eval trie (empty when unused).
proof_token proof0{};
proof_token proof1{};
};
namespace detail
@ -172,7 +178,8 @@ auto geneval_run(bool arith, bool arith_out, InputT x0, InputT x1,
InputT x0c = x0;
InputT x1c = x1;
proto.encode_walk_shares(x0c, x1c, arith);
const InputT alpha = utils::xor_input_shares(x0c, x1c);
// Keep the secret path on share-bits. Do not form a clear alpha for leaf
// placement, live levels, or correction seeds.
std::vector<InputT> flipped;
flipped.reserve(queries.size());
@ -191,8 +198,6 @@ auto geneval_run(bool arith, bool arith_out, InputT x0, InputT x1,
if (unique_leaves.size() > (std::size_t{1} << 20))
throw std::length_error("geneval trie is too large");
const uint64_t secret_leaf = geneval_leaf_id<dpf_type>(alpha);
constexpr auto to_int = utils::to_integral_type<InputT>{};
using tree = dpf::tree_traits<InteriorPRG>;
@ -222,14 +227,17 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
std::memset(&result.leaf, 0, sizeof(result.leaf));
result.correction_words.reserve(depth);
result.correction_advice.reserve(depth);
result.proof0 = detail::vdpf::zero_proof();
result.proof1 = detail::vdpf::zero_proof();
auto mask = dpf_type::msb_mask;
bool still_live = true;
uint64_t secret_prefix = 0;
for (std::size_t level = 0; level < depth; ++level, mask >>= 1)
{
const uint8_t bit0 = static_cast<uint8_t>(!!(to_int(mask) & to_int(x0c)));
const uint8_t bit1 = static_cast<uint8_t>(!!(to_int(mask) & to_int(x1c)));
const uint64_t parent_id = geneval_prefix(secret_leaf, depth, level);
const uint64_t parent_id = secret_prefix;
const bool is_last = tree::is_last_level(level, depth);
node L0 = simde_mm_setzero_si128();
@ -303,6 +311,8 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
const node cw0 = tree::pack_cw(cw, advice, false, is_last);
const node cw1 = tree::pack_cw(cw, advice, true, is_last);
const std::size_t child_bits = level + 1;
const uint8_t secret_bit = static_cast<uint8_t>((bit0 ^ bit1) & 1u);
secret_prefix = (secret_prefix << 1) | secret_bit;
std::vector<slot> next;
next.reserve(exps.size() * 2);
for (const exp & e : exps)
@ -322,9 +332,37 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
dpf::xor_if_lo_bit(e.R1, cw1, e.s1)});
}
}
// Fold every live child into both parties' VDPF tokens.
if (!next.empty())
{
cs_block cs{};
bool have_cs = false;
for (const slot & c : next)
{
if (c.id == secret_prefix)
{
// Prefix is the share-bit path accumulated above — not a
// fresh xor_input_shares of the point for leaf placement.
cs = detail::vdpf::make_cs(level, c.id, c.s0, c.s1);
have_cs = true;
break;
}
}
if (!have_cs)
cs = detail::vdpf::make_cs(level, next[0].id, next[0].s0,
next[0].s1);
for (const slot & c : next)
{
detail::vdpf::fold_node(result.proof0, level, c.id, c.s0, cs);
detail::vdpf::fold_node(result.proof1, level, c.id, c.s1, cs);
}
}
frontier = std::move(next);
}
const uint64_t secret_leaf = secret_prefix;
result.leaf_live = geneval_any_prefix(unique_leaves, depth, secret_leaf, depth);
if (result.leaf_live)
{
@ -343,18 +381,21 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
{
const uint8_t t0 = static_cast<uint8_t>(dpf::get_lo_bit(on->s0));
const uint8_t t1 = static_cast<uint8_t>(dpf::get_lo_bit(on->s1));
const std::size_t lane = static_cast<std::size_t>(to_int(alpha));
result.leaf = proto.template open_arith_leaf<ExteriorPRG, 0, outputs_tuple>(
dpf::unset_lo_2bits(on->s0), dpf::unset_lo_2bits(on->s1), t0, t1,
y0, y1, std::size_t{0}, lane);
y0, y1, std::size_t{0}, x0c, x1c);
}
else
{
const bool sign0 = dpf::get_lo_bit(on->s0);
auto built = dpf::make_leaves<ExteriorPRG>(alpha,
dpf::unset_lo_2bits(on->s0), dpf::unset_lo_2bits(on->s1), sign0,
std::size_t{0}, y0);
result.leaf = std::get<0>(built.first.first);
// Mux / reconstruct only inside the leaf protocol hook.
proto.open_leaf_group(x0c, x1c, [&](InputT sx0, InputT sx1) {
const InputT x = utils::xor_input_shares(sx0, sx1);
const bool sign0 = dpf::get_lo_bit(on->s0);
auto built = dpf::make_leaves<ExteriorPRG>(x,
dpf::unset_lo_2bits(on->s0), dpf::unset_lo_2bits(on->s1),
sign0, std::size_t{0}, y0);
result.leaf = std::get<0>(built.first.first);
});
}
}
@ -491,6 +532,10 @@ std::vector<InputT> geneval_inclusive(InputT from, InputT to)
/// @param rng the Doerner–Shelat randomness tapes
/// @param y the payload
/// @return the opened shares and correction words
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -512,6 +557,10 @@ auto geneval_point(InputT x0, InputT x1, InputT query,
/// @param rng the Doerner–Shelat randomness tapes
/// @param y the payload
/// @return the opened shares and correction words
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -534,6 +583,10 @@ auto geneval_point(arith_input_t, InputT x0, InputT x1, InputT query,
/// @param y0 party 0's share of the payload
/// @param y1 party 1's share of the payload
/// @return the opened shares and correction words
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -556,6 +609,10 @@ auto geneval_point(arith_output_t, InputT x0, InputT x1, InputT query,
/// @param y0 party 0's share of the payload
/// @param y1 party 1's share of the payload
/// @return the opened shares and correction words
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -586,6 +643,10 @@ auto geneval_point(arith_input_t, arith_output_t, InputT x0, InputT x1,
/// @param rng the Doerner–Shelat randomness tapes
/// @param y the `y`
/// @return Geneval on the inclusive interval `[from, to]`
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -600,6 +661,10 @@ auto geneval_interval(InputT x0, InputT x1, InputT from, InputT to,
detail::geneval_inclusive(from, to), rng.root, rng.pad, y);
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -614,7 +679,10 @@ auto geneval_interval(arith_input_t, InputT x0, InputT x1, InputT from,
detail::geneval_inclusive(from, to), rng.root, rng.pad, y);
}
/// @brief Geneval on the whole domain. Refuses a domain above 2^20 inputs.
/// @brief Geneval on the whole domain.
/// @details Materializes the query list. Domains wider than 20 bits refuse so
/// a caller does not allocate a `2^n` vector by accident. Prefer the
/// buffer overloads when writing into a pre-sized output scratch.
/// @tparam InteriorPRG PRG that expands interior nodes. Defaults to `dpf::prg::aes128`
/// @tparam ExteriorPRG PRG that expands the root. Defaults to `InteriorPRG`
/// @tparam InputT input domain type
@ -626,6 +694,10 @@ auto geneval_interval(arith_input_t, InputT x0, InputT x1, InputT from,
/// @param rng the Doerner–Shelat randomness tapes
/// @param y the `y`
/// @return Geneval on the whole domain
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -640,6 +712,10 @@ auto geneval_full(InputT x0, InputT x1,
detail::geneval_full_domain<InputT>(), rng.root, rng.pad, y);
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -669,6 +745,10 @@ auto geneval_full(arith_input_t, InputT x0, InputT x1,
/// @param rng the Doerner–Shelat randomness tapes
/// @param y the `y`
/// @return Geneval on a public sequence, in the order given
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -685,6 +765,10 @@ auto geneval_sequence(InputT x0, InputT x1, ForwardIterator begin,
std::move(qs), rng.root, rng.pad, y);
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -721,6 +805,8 @@ struct geneval_cmp_result
uint64_t addend1 = 0;
uint64_t mask = 0;
std::size_t live_levels = 0;
proof_token proof0{};
proof_token proof1{};
};
/// @name Comparison geneval
@ -762,7 +848,7 @@ geneval_cmp_result geneval_cmp(InputT x0, InputT x1,
return out;
auto keys = make_dpf_doerner_shelat(std::move(x0), std::move(x1),
std::move(rng), std::move(spec));
std::move(rng), std::move(spec), dpf::verifiable{});
const auto & k0 = keys.first;
const auto & k1 = keys.second;
using key_type = std::decay_t<decltype(k0)>;
@ -792,11 +878,19 @@ geneval_cmp_result geneval_cmp(InputT x0, InputT x1,
if constexpr (key_type::cmp_block == 0)
out.value_cw[level] = k0.value_cw(level);
}
detail::vdpf::init_proof(out.proof0, k0);
detail::vdpf::init_proof(out.proof1, k1);
auto path0 = make_basic_path_memoizer(k0);
auto path1 = make_basic_path_memoizer(k1);
for (auto it = begin; it != end; ++it)
{
out.party0.push_back(eval_point(dpf::cmp, k0, *it).raw());
out.party1.push_back(eval_point(dpf::cmp, k1, *it).raw());
out.party0.push_back(
detail::incr::eval_cmp_point_impl(k0, *it, path0, &out.proof0).raw());
out.party1.push_back(
detail::incr::eval_cmp_point_impl(k1, *it, path1, &out.proof1).raw());
}
detail::vdpf::fold_output_binding(out.proof0, k0);
detail::vdpf::fold_output_binding(out.proof1, k1);
return out;
}
@ -823,7 +917,7 @@ geneval_cmp_result geneval_cmp(arith_input_t, InputT x0, InputT x1,
return out;
auto keys = make_dpf_doerner_shelat(arith_input, std::move(x0), std::move(x1),
std::move(rng), std::move(spec));
std::move(rng), std::move(spec), dpf::verifiable{});
const auto & k0 = keys.first;
const auto & k1 = keys.second;
using key_type = std::decay_t<decltype(k0)>;
@ -853,11 +947,19 @@ geneval_cmp_result geneval_cmp(arith_input_t, InputT x0, InputT x1,
if constexpr (key_type::cmp_block == 0)
out.value_cw[level] = k0.value_cw(level);
}
detail::vdpf::init_proof(out.proof0, k0);
detail::vdpf::init_proof(out.proof1, k1);
auto path0 = make_basic_path_memoizer(k0);
auto path1 = make_basic_path_memoizer(k1);
for (auto it = begin; it != end; ++it)
{
out.party0.push_back(eval_point(dpf::cmp, k0, *it).raw());
out.party1.push_back(eval_point(dpf::cmp, k1, *it).raw());
out.party0.push_back(
detail::incr::eval_cmp_point_impl(k0, *it, path0, &out.proof0).raw());
out.party1.push_back(
detail::incr::eval_cmp_point_impl(k1, *it, path1, &out.proof1).raw());
}
detail::vdpf::fold_output_binding(out.proof0, k0);
detail::vdpf::fold_output_binding(out.proof1, k1);
return out;
}
@ -903,6 +1005,124 @@ geneval_cmp_result geneval_cmp(arith_input_t, InputT x0, InputT x1,
/// @}
namespace detail
{
/// @brief Copy party shares from a geneval result into caller buffers.
template <typename Result, typename Buf0, typename Buf1>
void geneval_fill_buffers(const Result & r, Buf0 & buf0, Buf1 & buf1)
{
const std::size_t n = r.party0.size();
if (utils::size(buf0) < n || utils::size(buf1) < n)
throw std::length_error("geneval: output buffer is too small");
for (std::size_t i = 0; i < n; ++i)
{
buf0[i] = r.party0[i];
buf1[i] = r.party1[i];
}
}
} // namespace detail
/// @name Geneval into caller buffers
/// @details Thin overloads that run the same trie walk, then copy party shares
/// into `buf0` / `buf1` (same layout as `eval_interval` / `eval_sequence`
/// output buffers). Memoizer arguments for the fused trie are internal;
/// path memoizers live on `geneval_cmp` / `geneval_ic`.
/// @{
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename Buf0,
typename Buf1>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_point(InputT x0, InputT x1, InputT query,
ds_randomness<RootSampler, PadRng> rng, OutputT y, Buf0 & buf0, Buf1 & buf1)
{
auto r = geneval_point<InteriorPRG, ExteriorPRG>(std::move(x0),
std::move(x1), query, std::move(rng), std::move(y));
detail::geneval_fill_buffers(r, buf0, buf1);
return r;
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename Buf0,
typename Buf1>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_interval(InputT x0, InputT x1, InputT from, InputT to,
ds_randomness<RootSampler, PadRng> rng, OutputT y, Buf0 & buf0, Buf1 & buf1)
{
auto r = geneval_interval<InteriorPRG, ExteriorPRG>(std::move(x0),
std::move(x1), from, to, std::move(rng), std::move(y));
detail::geneval_fill_buffers(r, buf0, buf1);
return r;
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename Buf0,
typename Buf1>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_full(InputT x0, InputT x1,
ds_randomness<RootSampler, PadRng> rng, OutputT y, Buf0 & buf0, Buf1 & buf1)
{
auto r = geneval_full<InteriorPRG, ExteriorPRG>(std::move(x0),
std::move(x1), std::move(rng), std::move(y));
detail::geneval_fill_buffers(r, buf0, buf1);
return r;
}
/// \complexity O(n F) PRG expansions. n is `depth`. Each level expands every frontier node (two `expand` calls, one per share) and, while the secret path is live, one `prepare_level`. F is at most the number of distinct query leaves; the function rejects more than 2^20. Setup sorts the q query ids.
/// \rounds No sockets. While the path is live, each level calls `prepare_level`, which samples one `ds_cw_pads` and two `ds_and_pads` and then `open_cw`.
/// \communication none in this function.
/// \preprocessing The `ds_randomness` tape: per live level, `ds_sample_cw` draws two 128-bit blocks and two bits, and each of the two AND pads is one `ds_sample_and`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename ForwardIterator,
typename Buf0,
typename Buf1>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_sequence(InputT x0, InputT x1, ForwardIterator begin,
ForwardIterator end, ds_randomness<RootSampler, PadRng> rng, OutputT y,
Buf0 & buf0, Buf1 & buf1)
{
auto r = geneval_sequence<InteriorPRG, ExteriorPRG>(std::move(x0),
std::move(x1), begin, end, std::move(rng), std::move(y));
detail::geneval_fill_buffers(r, buf0, buf1);
return r;
}
/// @}
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_GENEVAL_HPP__