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:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
|
|
@ -18,6 +18,7 @@
|
|||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
#include "dpf/interval_memoizer.hpp"
|
||||
#include "dpf/aligned_allocator.hpp"
|
||||
#include "dpf/leaf_node.hpp"
|
||||
#include "dpf/verifiable.hpp"
|
||||
|
||||
namespace dpf
|
||||
{
|
||||
|
|
@ -70,8 +72,10 @@ constexpr std::size_t resolved_out_prefix() noexcept
|
|||
// eval_point(target, key, x [, path])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = nonmemoizing_path_memoizer<KeyT>>
|
||||
typename PathMemoizer = nonmemoizing_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(out_t<I, N>, const KeyT & key, QueryT && x,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
|
|
@ -88,8 +92,10 @@ auto eval_point(out_t<I, N>, const KeyT & key, QueryT && x,
|
|||
}
|
||||
}
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>>
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(cmp_t, const KeyT & key, QueryT && x,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
|
|
@ -97,8 +103,41 @@ auto eval_point(cmp_t, const KeyT & key, QueryT && x,
|
|||
std::forward<PathMemoizer>(path));
|
||||
}
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(cmp_t, const KeyT & key, QueryT && x, prove_ref pr,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_point(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
auto out = detail::incr::eval_cmp_point_impl<Beta>(key, std::forward<QueryT>(x),
|
||||
std::forward<PathMemoizer>(path), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
return out;
|
||||
}
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(cmp_t, const KeyT & key, QueryT && x, sketch_ref & sk,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
static_assert(KeyT::is_extractable,
|
||||
"eval_point(cmp, ..., sketch(σ)): key must carry dpf::extractable");
|
||||
auto y = detail::incr::eval_cmp_point_impl<Beta>(key, std::forward<QueryT>(x),
|
||||
std::forward<PathMemoizer>(path));
|
||||
sk.absorb(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <std::size_t L, typename Beta = uint64_t, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>>
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(cmp_prefix_t<L>, const KeyT & key, QueryT && x,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
|
|
@ -106,12 +145,30 @@ auto eval_point(cmp_prefix_t<L>, const KeyT & key, QueryT && x,
|
|||
std::forward<QueryT>(x), std::forward<PathMemoizer>(path));
|
||||
}
|
||||
|
||||
/// \complexity O(n) time. n is `depth`. One interior traversal per level from the memoizer resume index through the leaf. Extra space is the path memoizer (O(n) nodes, or one node if it does not memoize). A proof token adds one fold per level walked.
|
||||
template <std::size_t L, typename Beta = uint64_t, typename KeyT, typename QueryT,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_point(cmp_prefix_t<L>, const KeyT & key, QueryT && x, prove_ref pr,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_point(cmp_prefix, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
auto out = detail::incr::eval_cmp_prefix_point_impl<L, Beta>(key,
|
||||
std::forward<QueryT>(x), std::forward<PathMemoizer>(path), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// eval_interval(target, key, from, to [, buf [, memo]])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer, typename IntervalMemoizer>
|
||||
typename OutputBuffer, typename IntervalMemoizer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf, IntervalMemoizer && memo)
|
||||
{
|
||||
|
|
@ -130,8 +187,10 @@ auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
|||
}
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer>
|
||||
typename OutputBuffer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf)
|
||||
{
|
||||
|
|
@ -148,7 +207,9 @@ auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT>
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to)
|
||||
{
|
||||
if constexpr (is_multilevel_key_v<KeyT>)
|
||||
|
|
@ -162,8 +223,10 @@ auto eval_interval(out_t<I, N>, const KeyT & key, LaneT from, LaneT to)
|
|||
}
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer>
|
||||
typename OutputBuffer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf)
|
||||
{
|
||||
|
|
@ -171,8 +234,25 @@ void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
|||
std::forward<OutputBuffer>(outbuf));
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer, typename IntervalMemoizer>
|
||||
typename OutputBuffer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_interval(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
detail::incr::eval_cmp_interval_impl<Beta>(key, from, to,
|
||||
std::forward<OutputBuffer>(outbuf), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer, typename IntervalMemoizer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf, IntervalMemoizer && memo)
|
||||
{
|
||||
|
|
@ -181,18 +261,51 @@ void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
|||
std::forward<IntervalMemoizer>(memo));
|
||||
}
|
||||
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT>
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename OutputBuffer, typename IntervalMemoizer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
OutputBuffer && outbuf, IntervalMemoizer && memo, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_interval(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
detail::incr::eval_cmp_interval_impl<Beta>(key, from, to,
|
||||
std::forward<OutputBuffer>(outbuf),
|
||||
std::forward<IntervalMemoizer>(memo), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to)
|
||||
{
|
||||
return detail::incr::eval_cmp_interval_impl<Beta>(key, from, to);
|
||||
}
|
||||
|
||||
/// \complexity O(L) interior traversals and O(L) workspace in the basic memoizer. L is the number of leaf nodes covering the closed interval (`get_nodes_at_level` at `depth`). Level k expands `(to >> (n-k)) - (from >> (n-k)) + 1` nodes; those counts sum to Θ(L). The output buffer holds one slot per input in the interval. n is `depth`.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_interval(cmp_t, const KeyT & key, LaneT from, LaneT to, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_interval(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
auto out = detail::incr::eval_cmp_interval_impl<Beta>(key, from, to, &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// eval_full(target, key [, …])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// \complexity Same expansion as `eval_interval` on the whole domain. L = 2^{n - lg(outputs_per_leaf)} leaf nodes, n = `depth`. Time Θ(L) interior traversals. The output buffer stores one slot per domain point (2^n).
|
||||
template <std::size_t I, std::size_t N, typename KeyT,
|
||||
typename OutputBuffer, typename IntervalMemoizer>
|
||||
typename OutputBuffer, typename IntervalMemoizer,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_full(out_t<I, N>, const KeyT & key, OutputBuffer && outbuf,
|
||||
IntervalMemoizer && memo)
|
||||
{
|
||||
|
|
@ -210,7 +323,9 @@ auto eval_full(out_t<I, N>, const KeyT & key, OutputBuffer && outbuf,
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N, typename KeyT>
|
||||
/// \complexity Same expansion as `eval_interval` on the whole domain. L = 2^{n - lg(outputs_per_leaf)} leaf nodes, n = `depth`. Time Θ(L) interior traversals. The output buffer stores one slot per domain point (2^n).
|
||||
template <std::size_t I, std::size_t N, typename KeyT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_full(out_t<I, N>, const KeyT & key)
|
||||
{
|
||||
if constexpr (is_multilevel_key_v<KeyT>)
|
||||
|
|
@ -224,7 +339,9 @@ auto eval_full(out_t<I, N>, const KeyT & key)
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Beta = uint64_t, typename KeyT>
|
||||
/// \complexity Same expansion as `eval_interval` on the whole domain. L = 2^{n - lg(outputs_per_leaf)} leaf nodes, n = `depth`. Time Θ(L) interior traversals. The output buffer stores one slot per domain point (2^n).
|
||||
template <typename Beta = uint64_t, typename KeyT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_full(cmp_t, const KeyT & key)
|
||||
{
|
||||
if (!key.has_cmp())
|
||||
|
|
@ -238,13 +355,36 @@ auto eval_full(cmp_t, const KeyT & key)
|
|||
return detail::incr::eval_cmp_interval_impl<Beta>(key, lo, hi);
|
||||
}
|
||||
|
||||
/// \complexity Same expansion as `eval_interval` on the whole domain. L = 2^{n - lg(outputs_per_leaf)} leaf nodes, n = `depth`. Time Θ(L) interior traversals. The output buffer stores one slot per domain point (2^n).
|
||||
template <typename Beta = uint64_t, typename KeyT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_full(cmp_t, const KeyT & key, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_full(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
if (!key.has_cmp())
|
||||
throw std::invalid_argument("eval_full(cmp): no comparison channel");
|
||||
using lane_t = typename KeyT::integral_type;
|
||||
const auto nbits = static_cast<std::size_t>(key.cmp().nbits);
|
||||
const lane_t lo = 0;
|
||||
const lane_t hi = (nbits >= 8 * sizeof(lane_t))
|
||||
? static_cast<lane_t>(~lane_t{0})
|
||||
: static_cast<lane_t>((lane_t{1} << nbits) - 1);
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
auto out = detail::incr::eval_cmp_interval_impl<Beta>(key, lo, hi, &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
return out;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// eval_sequence(target, key, begin, end, buf [, path])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// \complexity O(n k) interior traversals in the worst case and O(k) node workspace. k is the number of listed points and n is `depth`. The breadth-first buffer is 2k nodes, so each level traverses at most one node per point. Shared prefixes do fewer traversals. A recipe memoizer instead stores O(recipe leaf nodes) (see that memoizer).
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename ForwardIterator,
|
||||
typename OutputBuffer,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>>
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_sequence(out_t<I, N>, const KeyT & key, ForwardIterator begin,
|
||||
ForwardIterator end, OutputBuffer && outbuf,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
|
|
@ -263,9 +403,11 @@ auto eval_sequence(out_t<I, N>, const KeyT & key, ForwardIterator begin,
|
|||
}
|
||||
}
|
||||
|
||||
/// \complexity O(n k) interior traversals in the worst case and O(k) node workspace. k is the number of listed points and n is `depth`. The breadth-first buffer is 2k nodes, so each level traverses at most one node per point. Shared prefixes do fewer traversals. A recipe memoizer instead stores O(recipe leaf nodes) (see that memoizer).
|
||||
template <typename Beta = uint64_t, typename KeyT, typename ForwardIterator,
|
||||
typename OutputBuffer,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>>
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_sequence(cmp_t, const KeyT & key, ForwardIterator begin,
|
||||
ForwardIterator end, OutputBuffer && outbuf,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
|
|
@ -275,24 +417,45 @@ void eval_sequence(cmp_t, const KeyT & key, ForwardIterator begin,
|
|||
std::forward<PathMemoizer>(path));
|
||||
}
|
||||
|
||||
/// \complexity O(n k) interior traversals in the worst case and O(k) node workspace. k is the number of listed points and n is `depth`. The breadth-first buffer is 2k nodes, so each level traverses at most one node per point. Shared prefixes do fewer traversals. A recipe memoizer instead stores O(recipe leaf nodes) (see that memoizer).
|
||||
template <typename Beta = uint64_t, typename KeyT, typename ForwardIterator,
|
||||
typename OutputBuffer,
|
||||
typename PathMemoizer = basic_path_memoizer<KeyT>,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_sequence(cmp_t, const KeyT & key, ForwardIterator begin,
|
||||
ForwardIterator end, OutputBuffer && outbuf, prove_ref pr,
|
||||
PathMemoizer && path = PathMemoizer{})
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_sequence(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
detail::incr::eval_cmp_sequence_impl<Beta>(key, begin, end,
|
||||
std::forward<OutputBuffer>(outbuf),
|
||||
std::forward<PathMemoizer>(path), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// make_output_buffer(target, …)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template <typename Beta = uint64_t, typename KeyT>
|
||||
template <typename Beta = uint64_t, typename KeyT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto make_output_buffer(cmp_t, const KeyT & key, std::size_t n)
|
||||
{
|
||||
return detail::incr::make_output_buffer_for_cmp_impl<Beta>(key, n);
|
||||
}
|
||||
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT>
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto make_output_buffer(cmp_t, const KeyT & key, LaneT from, LaneT to)
|
||||
{
|
||||
return detail::incr::make_output_buffer_for_cmp_interval_impl<Beta>(
|
||||
key, from, to);
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT>
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto make_output_buffer(out_t<I, N>, const KeyT & key, LaneT from, LaneT to)
|
||||
{
|
||||
constexpr auto pref = detail::resolved_out_prefix<I, N, KeyT>();
|
||||
|
|
@ -426,6 +589,7 @@ auto eval_out_inner_product_impl(const KeyT & dpf, LaneT from, LaneT to,
|
|||
for (std::size_t j = 0; j < count; ++j)
|
||||
{
|
||||
auto leaf = dpf.template traverse_exterior<I>(nodes[j]);
|
||||
detail::incr::absorb_public_addend_all_lanes<I>(dpf, leaf);
|
||||
acc.mac(leaf, (start + j) * opl, opl, weights);
|
||||
}
|
||||
start += seg.count;
|
||||
|
|
@ -436,7 +600,7 @@ auto eval_out_inner_product_impl(const KeyT & dpf, LaneT from, LaneT to,
|
|||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename Weights>
|
||||
Beta eval_cmp_inner_product_impl(const KeyT & dpf, LaneT from, LaneT to,
|
||||
Weights && weights)
|
||||
Weights && weights, proof_token * pi = nullptr)
|
||||
{
|
||||
if (!dpf.has_cmp())
|
||||
throw std::invalid_argument("cmp inner product: no comparison channel");
|
||||
|
|
@ -459,7 +623,7 @@ Beta eval_cmp_inner_product_impl(const KeyT & dpf, LaneT from, LaneT to,
|
|||
const std::size_t levels = unwrap_party_key_t<KeyT>::cmp_block > 0
|
||||
? unwrap_party_key_t<KeyT>::cmp_h : nbits;
|
||||
detail::incr::eval_cmp_interval_impl_interior(dpf, a, cmp_exclusive_end(b),
|
||||
nbits, memo, levels);
|
||||
nbits, memo, levels, pi);
|
||||
|
||||
uint64_t dot = 0;
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
|
|
@ -486,9 +650,11 @@ Beta eval_cmp_inner_product_impl(const KeyT & dpf, LaneT from, LaneT to,
|
|||
} // namespace incr
|
||||
} // namespace detail
|
||||
|
||||
/// \complexity Same interior expansion as `eval_interval` on `[from, to]` (Θ(L) nodes, L = leaf nodes in the interval) plus a multiply-add per output slot into an O(1) accumulator. The basic memoizer still holds O(L) nodes.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
typename Weights, typename IntervalMemoizer,
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true>
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_inner_product(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
||||
Weights && weights, IntervalMemoizer && memo)
|
||||
{
|
||||
|
|
@ -498,20 +664,24 @@ auto eval_inner_product(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
|||
std::forward<IntervalMemoizer>(memo));
|
||||
}
|
||||
|
||||
/// \complexity Same interior expansion as `eval_interval` on `[from, to]` (Θ(L) nodes, L = leaf nodes in the interval) plus a multiply-add per output slot into an O(1) accumulator. The basic memoizer still holds O(L) nodes.
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename LaneT,
|
||||
typename Weights,
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true>
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_inner_product(out_t<I, N>, const KeyT & key, LaneT from, LaneT to,
|
||||
Weights && weights)
|
||||
{
|
||||
auto memo = make_basic_interval_memoizer<KeyT, I>(from, to);
|
||||
auto memo = make_basic_interval_memoizer<KeyT, I>(key, from, to);
|
||||
constexpr auto pref = detail::resolved_out_prefix<I, N, KeyT>();
|
||||
return detail::incr::eval_out_inner_product_impl<pref, I>(key, from, to,
|
||||
std::forward<Weights>(weights), memo);
|
||||
}
|
||||
|
||||
/// \complexity Same interior expansion as `eval_interval` on `[from, to]` (Θ(L) nodes, L = leaf nodes in the interval) plus a multiply-add per output slot into an O(1) accumulator. The basic memoizer still holds O(L) nodes.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename Weights>
|
||||
typename Weights,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
Beta eval_inner_product(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
Weights && weights)
|
||||
{
|
||||
|
|
@ -519,6 +689,106 @@ Beta eval_inner_product(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
|||
std::forward<Weights>(weights));
|
||||
}
|
||||
|
||||
/// @brief Comparison inner product over the whole comparison domain.
|
||||
/// @details `sum_x [x satisfies cmp] * weights[x]` (as complementary halves),
|
||||
/// the full-domain form of `eval_inner_product(cmp, key, lo, hi, w)`.
|
||||
/// Pair the two parties' results with `reconstruct_cmp_halves`.
|
||||
/// Waldo's private-threshold aggregate is this one call.
|
||||
/// \complexity Same expansion as `eval_full` on the comparison domain, plus a
|
||||
/// multiply-add per point into an `O(1)` accumulator.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename Weights,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
Beta eval_full_inner_product(cmp_t, const KeyT & key, Weights && weights)
|
||||
{
|
||||
if (!key.has_cmp())
|
||||
throw std::invalid_argument(
|
||||
"eval_full_inner_product(cmp): no comparison channel");
|
||||
using lane_t = typename KeyT::integral_type;
|
||||
const auto nbits = static_cast<std::size_t>(key.cmp().nbits);
|
||||
const lane_t lo = 0;
|
||||
const lane_t hi = (nbits >= 8 * sizeof(lane_t))
|
||||
? static_cast<lane_t>(~lane_t{0})
|
||||
: static_cast<lane_t>((lane_t{1} << nbits) - 1);
|
||||
return eval_inner_product<Beta>(cmp, key, lo, hi,
|
||||
std::forward<Weights>(weights));
|
||||
}
|
||||
|
||||
/// \complexity Same interior expansion as `eval_interval` on `[from, to]` (Θ(L) nodes, L = leaf nodes in the interval) plus a multiply-add per output slot into an O(1) accumulator. The basic memoizer still holds O(L) nodes.
|
||||
template <typename Beta = uint64_t, typename KeyT, typename LaneT,
|
||||
typename Weights,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
Beta eval_inner_product(cmp_t, const KeyT & key, LaneT from, LaneT to,
|
||||
Weights && weights, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"eval_inner_product(cmp, ..., prove(π)): key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
auto out = detail::incr::eval_cmp_inner_product_impl<Beta>(key, from, to,
|
||||
std::forward<Weights>(weights), &pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
return out;
|
||||
}
|
||||
|
||||
/// @brief Initialise `pr.token` and fold `[from, to]` once per cmp BFS node.
|
||||
template <typename KeyT, typename LaneT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void prove_cmp_interval(const KeyT & key, LaneT from, LaneT to, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"prove_cmp_interval: key must carry dpf::verifiable");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
detail::incr::prove_fold_cmp_interval(key, from, to, pr.token);
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
}
|
||||
|
||||
/// @brief Initialise `pr.token` and fold the full comparison domain.
|
||||
template <typename KeyT,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void prove_cmp_full(const KeyT & key, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"prove_cmp_full: key must carry dpf::verifiable");
|
||||
if (!key.has_cmp())
|
||||
throw std::invalid_argument("prove_cmp_full: no comparison channel");
|
||||
using lane_t = typename KeyT::integral_type;
|
||||
const auto nbits = static_cast<std::size_t>(key.cmp().nbits);
|
||||
const lane_t lo = 0;
|
||||
const lane_t hi = (nbits >= 8 * sizeof(lane_t))
|
||||
? static_cast<lane_t>(~lane_t{0})
|
||||
: static_cast<lane_t>((lane_t{1} << nbits) - 1);
|
||||
prove_cmp_interval(key, lo, hi, pr);
|
||||
}
|
||||
|
||||
/// @brief Fold a sorted sequence into `pr` via cmp interval-run covers.
|
||||
template <typename KeyT, typename ForwardIterator,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void prove_cmp_sequence(const KeyT & key, ForwardIterator begin,
|
||||
ForwardIterator end, prove_ref pr)
|
||||
{
|
||||
static_assert(KeyT::is_verifiable,
|
||||
"prove_cmp_sequence: key must carry dpf::verifiable");
|
||||
if (HEDLEY_UNLIKELY(begin != end && !std::is_sorted(begin, end)))
|
||||
throw std::runtime_error("list must be sorted");
|
||||
detail::vdpf::init_proof(pr.token, key);
|
||||
using lane_t = typename KeyT::integral_type;
|
||||
for (auto it = begin; it != end; )
|
||||
{
|
||||
const auto run_from = static_cast<lane_t>(*it);
|
||||
auto run_to = run_from;
|
||||
++it;
|
||||
while (it != end)
|
||||
{
|
||||
const auto next = static_cast<lane_t>(*it);
|
||||
if (next != static_cast<lane_t>(run_to + lane_t{1}))
|
||||
break;
|
||||
run_to = next;
|
||||
++it;
|
||||
}
|
||||
detail::incr::prove_fold_cmp_interval(key, run_from, run_to, pr.token);
|
||||
}
|
||||
detail::vdpf::fold_output_binding(pr.token, key);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// eval_sequence_breadth_first(out<I>, key, begin, end [, outbuf])
|
||||
//
|
||||
|
|
@ -621,6 +891,8 @@ void eval_out_sequence_breadth_first_impl(const KeyT & dpf,
|
|||
auto leaf = dpf.template traverse_exterior<I>(buf[j]);
|
||||
const std::size_t off =
|
||||
static_cast<std::size_t>(static_cast<input_type>(*curr) & (opl - 1));
|
||||
detail::incr::absorb_public_addend_lane<I>(dpf, leaf,
|
||||
static_cast<input_type>(off));
|
||||
auto v = dpf::extract_leaf<exterior_node, output_type>(leaf, off);
|
||||
if constexpr (is_party_key_v<KeyT>)
|
||||
outbuf[i] = subtractive_share<output_type, party_of_v<KeyT>>::from_raw(v);
|
||||
|
|
@ -633,9 +905,11 @@ void eval_out_sequence_breadth_first_impl(const KeyT & dpf,
|
|||
} // namespace incr
|
||||
} // namespace detail
|
||||
|
||||
/// \complexity O(n k) interior traversals in the worst case and O(k) node workspace. k is the number of listed points and n is `depth`. The breadth-first buffer is 2k nodes, so each level traverses at most one node per point. Shared prefixes do fewer traversals. A recipe memoizer instead stores O(recipe leaf nodes) (see that memoizer).
|
||||
template <std::size_t I, std::size_t N, typename KeyT,
|
||||
typename ForwardIterator, typename OutputBuffer,
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true>
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
void eval_sequence_breadth_first(out_t<I, N>, const KeyT & key,
|
||||
ForwardIterator begin, ForwardIterator end, OutputBuffer && outbuf)
|
||||
{
|
||||
|
|
@ -644,9 +918,11 @@ void eval_sequence_breadth_first(out_t<I, N>, const KeyT & key,
|
|||
std::forward<OutputBuffer>(outbuf));
|
||||
}
|
||||
|
||||
/// \complexity O(n k) interior traversals in the worst case and O(k) node workspace. k is the number of listed points and n is `depth`. The breadth-first buffer is 2k nodes, so each level traverses at most one node per point. Shared prefixes do fewer traversals. A recipe memoizer instead stores O(recipe leaf nodes) (see that memoizer).
|
||||
template <std::size_t I, std::size_t N, typename KeyT,
|
||||
typename ForwardIterator,
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true>
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto eval_sequence_breadth_first(out_t<I, N>, const KeyT & key,
|
||||
ForwardIterator begin, ForwardIterator end)
|
||||
{
|
||||
|
|
@ -668,7 +944,8 @@ auto eval_sequence_breadth_first(out_t<I, N>, const KeyT & key,
|
|||
/// @param end the iterator past the last query
|
||||
/// @return the constructed object
|
||||
template <std::size_t I, std::size_t N, typename KeyT, typename ForwardIterator,
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true>
|
||||
std::enable_if_t<is_multilevel_key_v<KeyT>, bool> = true,
|
||||
std::enable_if_t<!has_embedded_dpf_key_v<std::decay_t<KeyT>>, int> = 0>
|
||||
auto make_sequence_recipe(out_t<I, N>, const KeyT & key, ForwardIterator begin,
|
||||
ForwardIterator end)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue