Document the new DPF surfaces in one command set, and test the field, half-tree, and multipoint edges.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0d8a5a8131
commit
0dff6df8ed
250 changed files with 12199 additions and 1981 deletions
|
|
@ -1,6 +1,5 @@
|
|||
/// @file dpf/dpf_key.hpp
|
||||
/// @brief
|
||||
/// @details
|
||||
/// @brief The DPF key, its correction words, and interior traversal.
|
||||
/// @author Ryan Henry <ryan.henry@ucalgary.ca>
|
||||
/// @copyright Copyright (c) 2019-2024 Ryan Henry and [others](@ref authors)
|
||||
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
|
||||
|
|
@ -19,6 +18,7 @@
|
|||
#include <atomic>
|
||||
|
||||
#include "dpf/prg_aes.hpp"
|
||||
#include "dpf/tree_traits.hpp"
|
||||
#include "dpf/wildcard.hpp"
|
||||
#include "dpf/twiddle.hpp"
|
||||
#include "dpf/leaf_node.hpp"
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include "dpf/leaf_wrapper.hpp"
|
||||
#include "dpf/emplace.hpp"
|
||||
#include "dpf/placement.hpp"
|
||||
#include "dpf/verifiable.hpp"
|
||||
#include "dpf/dcf.hpp"
|
||||
|
||||
namespace dpf
|
||||
|
|
@ -88,16 +89,25 @@ auto make_dpfargs(InputT && x, OutputT && y, OutputTs && ...ys)
|
|||
std::forward<OutputTs>(ys)...) };
|
||||
}
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
template <typename InteriorPRG>
|
||||
using root_sampler_t = std::add_pointer_t<typename InteriorPRG::block_type()>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Classic single-level DPF key body (all outputs bare, at full input width,
|
||||
/// @brief Classic single-level DPF key body (all outputs bare, at full input width,
|
||||
/// equal widths, no comparison channel). `Derived` is the public `dpf_key`
|
||||
/// specialization that inherits this body — threaded through only so that
|
||||
/// `emplace`/`emplace_back` construct the public key type.
|
||||
/// @tparam Derived derived
|
||||
/// @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
|
||||
/// @tparam OutputT output type
|
||||
/// @tparam OutputTs output ts
|
||||
template <typename Derived,
|
||||
typename InteriorPRG,
|
||||
typename ExteriorPRG,
|
||||
|
|
@ -108,6 +118,7 @@ struct classic_dpf_key_impl
|
|||
{
|
||||
public:
|
||||
using interior_prg = InteriorPRG;
|
||||
using tree = dpf::tree_traits<InteriorPRG>;
|
||||
using interior_node = typename InteriorPRG::block_type;
|
||||
|
||||
using exterior_prg = ExteriorPRG;
|
||||
|
|
@ -156,9 +167,18 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
static constexpr std::size_t cmp_h = 0;
|
||||
static constexpr std::size_t cmp_checkpoints = 0;
|
||||
static constexpr std::size_t cmp_tail = 0;
|
||||
/// Classic keys are single-level; the unified eval surface keeps routing
|
||||
/// @brief Classic keys are single-level; the unified eval surface keeps routing
|
||||
/// them through the classic `eval_*` fast paths (see `is_multilevel_key`).
|
||||
/// @see `is_multilevel_key`
|
||||
static constexpr bool is_multilevel = false;
|
||||
static constexpr bool is_verifiable = false;
|
||||
static constexpr bool is_extractable = false;
|
||||
using correction_seeds_array = std::array<cs_block, 0>;
|
||||
const correction_seeds_array & correction_seeds() const
|
||||
{
|
||||
static const correction_seeds_array empty{};
|
||||
return empty;
|
||||
}
|
||||
|
||||
private:
|
||||
using meta_placed_tuple = std::tuple<
|
||||
|
|
@ -178,7 +198,10 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
static constexpr std::size_t outputs_per_leaf_of =
|
||||
std::size_t{1} << lg_outputs_per_leaf_of<I>;
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
using correction_words_array = std::array<interior_node, depth>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
using correction_advice_array = std::array<psnip_uint8_t, depth>;
|
||||
|
||||
template <typename Emplaceable>
|
||||
|
|
@ -267,8 +290,9 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
HEDLEY_ALWAYS_INLINE
|
||||
auto correction_word(std::size_t level, bool direction) const
|
||||
{
|
||||
return set_lo_bit(correction_word(level),
|
||||
(correction_advice_[level] >> direction) & 1);
|
||||
return tree::pack_cw(correction_word(level),
|
||||
correction_advice_[level], direction,
|
||||
tree::is_last_level(level, depth));
|
||||
}
|
||||
|
||||
template <std::size_t I = 0>
|
||||
|
|
@ -318,58 +342,46 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
static auto traverse_interior(const interior_node & node,
|
||||
const interior_node & cw, bool dir) noexcept
|
||||
const interior_node & cw, bool dir, bool is_last = false) noexcept
|
||||
{
|
||||
return dpf::xor_if_lo_bit(
|
||||
interior_prg::eval(unset_lo_2bits(node), dir), cw, node);
|
||||
return tree::traverse(node, cw, dir, is_last);
|
||||
}
|
||||
|
||||
/// Expand both children of `node` with one pipelined `eval01`.
|
||||
/// Equivalent to `traverse_interior(node, cw0, 0)` and
|
||||
/// `traverse_interior(node, cw1, 1)`, but the two AES-128 blocks share
|
||||
/// a round loop. Full-domain interval eval uses this at almost every
|
||||
/// interior parent.
|
||||
/// @brief Expand both children of `node` with one pipelined expand.
|
||||
/// @details Equivalent to `traverse_interior(node, cw0, 0)` and
|
||||
/// `traverse_interior(node, cw1, 1)`. Full-domain interval eval uses this
|
||||
/// at almost every interior parent.
|
||||
/// @param node the GGM node
|
||||
/// @param cw0 correction word for the left child
|
||||
/// @param cw1 correction word for the right child
|
||||
/// @param is_last whether this is the last interior level
|
||||
/// @return both children of `node`
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
static auto traverse_interior01(const interior_node & node,
|
||||
const interior_node & cw0, const interior_node & cw1) noexcept
|
||||
const interior_node & cw0, const interior_node & cw1,
|
||||
bool is_last = false) noexcept
|
||||
{
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto kids = interior_prg::eval01(unset_lo_2bits(node));
|
||||
return std::array<interior_node, 2>{
|
||||
dpf::xor_if_lo_bit(kids[0], cw0, node),
|
||||
dpf::xor_if_lo_bit(kids[1], cw1, node)
|
||||
};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
return tree::traverse01(node, cw0, cw1, is_last);
|
||||
}
|
||||
|
||||
/// Four independent `traverse_interior01` via `InteriorPRG::eval01_x4`.
|
||||
/// `left[i]` / `right[i]` are the children of `parents[i]`.
|
||||
/// @brief Four independent `traverse_interior01` via traits batched expand.
|
||||
/// @details `left[i]` / `right[i]` are the children of `parents[i]`.
|
||||
/// @param parents the `parents`
|
||||
/// @param cw0 the `cw0`
|
||||
/// @param cw1 the `cw1`
|
||||
/// @param left the `left`
|
||||
/// @param right the `right`
|
||||
/// @param is_last the `is_last`
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
static void traverse_interior01_x4(const interior_node * HEDLEY_RESTRICT parents,
|
||||
const interior_node & cw0, const interior_node & cw1,
|
||||
interior_node * HEDLEY_RESTRICT left,
|
||||
interior_node * HEDLEY_RESTRICT right) noexcept
|
||||
interior_node * HEDLEY_RESTRICT right, bool is_last = false) noexcept
|
||||
{
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
alignas(interior_node) interior_node seeds[4];
|
||||
DPF_UNROLL_LOOP
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
seeds[i] = unset_lo_2bits(parents[i]);
|
||||
}
|
||||
interior_prg::eval01_x4(seeds, left, right);
|
||||
DPF_UNROLL_LOOP
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
left[i] = dpf::xor_if_lo_bit(left[i], cw0, parents[i]);
|
||||
right[i] = dpf::xor_if_lo_bit(right[i], cw1, parents[i]);
|
||||
}
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
tree::traverse01_x4(parents, cw0, cw1, left, right, is_last);
|
||||
}
|
||||
|
||||
template <std::size_t I = 0,
|
||||
|
|
@ -383,11 +395,11 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
using output_type = std::tuple_element_t<I, concrete_outputs_tuple>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
// Subtractive share: CW_if_t − mask so reconstruct(y0, y1) = y0 − y1 = β.
|
||||
return dpf::subtract_leaf<output_type>(
|
||||
dpf::get_if_lo_bit(correction_word, node),
|
||||
make_leaf_mask_inner<exterior_prg, I, concrete_outputs_tuple>(unset_lo_2bits(node)));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
}
|
||||
|
||||
template <std::size_t I = 0>
|
||||
|
|
@ -414,9 +426,12 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
{
|
||||
return std::apply([&leaf..., &beaver...](auto & ...foo)
|
||||
{
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
return std::make_tuple(
|
||||
dpf::leaf_wrapper<std::decay_t<decltype(foo)>, exterior_node>(leaf, beaver)...
|
||||
);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
}, tmp);
|
||||
}, beavers);
|
||||
}, leaves);
|
||||
|
|
@ -439,16 +454,21 @@ namespace detail
|
|||
namespace incr
|
||||
{
|
||||
|
||||
/// Comparison-channel storage. Value CWs, `cw_last`, and the `cmp_addend`
|
||||
/// @brief Comparison-channel storage. Value CWs, `cw_last`, and the `cmp_addend`
|
||||
/// share are held at the comparison group width (`ValueCwWord`), not a full
|
||||
/// padded `uint64_t` per level: a bit comparison carries 1 byte/level, a
|
||||
/// `uint16_t` payload 2 bytes/level, etc. Arithmetic still runs in `uint64_t`
|
||||
/// (masked); the narrow word is only the on-key / on-wire representation.
|
||||
/// Extra per-level δ-coefficients kept only for wildcard comparison payloads
|
||||
/// @details Extra per-level δ-coefficients kept only for wildcard comparison payloads
|
||||
/// (empty for concrete cmp keys, so their layout is unchanged). The value CWs
|
||||
/// / `cw_last` are affine in the payload δ, so after keygen with δ = 0 the
|
||||
/// concrete values are `base[i] + coeff[i]·δ`; `assign_cmp` patches them in
|
||||
/// place with no tree re-walk / re-PRG.
|
||||
/// @tparam Depth depth
|
||||
/// @tparam ValueCwWord value cw word
|
||||
/// @tparam Wild whether the payload is a wildcard
|
||||
/// @tparam TailLen tail len
|
||||
/// @tparam Idcf idcf
|
||||
template <std::size_t Depth, typename ValueCwWord, bool Wild,
|
||||
std::size_t TailLen = 0, bool Idcf = false>
|
||||
struct cmp_wild_state { };
|
||||
|
|
@ -520,6 +540,10 @@ struct cmp_storage
|
|||
return static_cast<uint64_t>(value_cw_[level]);
|
||||
}
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cw_last_word() const noexcept { return cw_last_; }
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cmp_addend_word() const noexcept { return cmp_addend_; }
|
||||
HEDLEY_NO_THROW
|
||||
uint64_t cw_last() const noexcept { return static_cast<uint64_t>(cw_last_); }
|
||||
HEDLEY_NO_THROW
|
||||
const tail_array & tail_cw() const noexcept { return tail_; }
|
||||
|
|
@ -553,9 +577,11 @@ struct cmp_storage
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Patch the (public) value CWs / `cw_last` in place for a resolved δ and
|
||||
/// @brief Patch the (public) value CWs / `cw_last` in place for a resolved δ and
|
||||
/// install this party's `cmp_addend` share. No-op on the CWs when there is
|
||||
/// no wildcard coefficient table (trivial domain-edge cmp).
|
||||
/// @param delta the payload difference `if_true - if_false`
|
||||
/// @param addend_share the `addend_share`
|
||||
void assign_cmp_delta(uint64_t delta, uint64_t addend_share)
|
||||
{
|
||||
static_assert(Wild,
|
||||
|
|
@ -595,6 +621,117 @@ struct cmp_storage
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief Overwrite the public final correction and this party's addend. Used when
|
||||
/// the group element does not fit in the `uint64_t` the constructor takes.
|
||||
/// @param last the past-the-end element of the range
|
||||
/// @param addend the additive share of the off-point payload
|
||||
/// @param last_coeff the `last_coeff`
|
||||
void set_scalars(value_cw_word last, value_cw_word addend,
|
||||
value_cw_word last_coeff)
|
||||
{
|
||||
cw_last_ = last;
|
||||
cmp_addend_ = addend;
|
||||
if constexpr (Wild)
|
||||
wild_.cw_last_coeff = last_coeff;
|
||||
else
|
||||
(void)last_coeff;
|
||||
}
|
||||
|
||||
/// @brief `base + coeff · δ` in `delta`'s group, then install `addend`.
|
||||
/// @param delta the payload difference `if_true - if_false`
|
||||
/// @param addend the additive share of the off-point payload
|
||||
void assign_group(const detail::group_elem & delta, value_cw_word addend)
|
||||
{
|
||||
static_assert(Wild,
|
||||
"assign_cmp on a key whose comparison payload is not a wildcard");
|
||||
if constexpr (Wild)
|
||||
{
|
||||
auto mix = [&](value_cw_word base_w, value_cw_word coeff_w) {
|
||||
const auto base = detail::group_from_word(base_w, delta);
|
||||
const auto coeff = detail::group_from_word(coeff_w, delta);
|
||||
return detail::group_to_word<value_cw_word>(
|
||||
detail::group_add(base, detail::group_mul(coeff, delta)));
|
||||
};
|
||||
for (std::size_t i = 0; i < Depth; ++i)
|
||||
value_cw_[i] = mix(value_cw_[i], wild_.value_cw_coeff[i]);
|
||||
if constexpr (Blocked)
|
||||
{
|
||||
for (std::size_t i = 0; i < TailLen; ++i)
|
||||
tail_[i] = mix(tail_[i], wild_.tail_coeff[i]);
|
||||
}
|
||||
cw_last_ = mix(cw_last_, wild_.cw_last_coeff);
|
||||
if constexpr (Idcf)
|
||||
{
|
||||
for (std::size_t i = 0; i < prefix_cw_len; ++i)
|
||||
prefix_cw_[i] = mix(prefix_cw_[i], wild_.prefix_cw_coeff[i]);
|
||||
}
|
||||
cmp_addend_ = addend;
|
||||
wild_.assigned = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Per-level δ coefficients for a wildcard comparison. Empty when the
|
||||
/// payload is concrete.
|
||||
/// @return the coefficient table
|
||||
const value_cw_array & value_cw_coeff() const noexcept
|
||||
{
|
||||
if constexpr (Wild)
|
||||
return wild_.value_cw_coeff;
|
||||
else
|
||||
{
|
||||
static const value_cw_array empty{};
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Coefficient of δ in `cw_last`. Zero when the payload is concrete.
|
||||
/// @return the final coefficient word
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cw_last_coeff_word() const noexcept
|
||||
{
|
||||
if constexpr (Wild)
|
||||
return wild_.cw_last_coeff;
|
||||
else
|
||||
return value_cw_word{};
|
||||
}
|
||||
|
||||
/// @brief Tail δ coefficients for a blocked wildcard comparison.
|
||||
/// @return the tail coefficient table
|
||||
const tail_array & tail_coeff() const noexcept
|
||||
{
|
||||
if constexpr (Wild)
|
||||
return wild_.tail_coeff;
|
||||
else
|
||||
{
|
||||
static const tail_array empty{};
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Prefix δ coefficients for an iDCF wildcard comparison.
|
||||
/// @return the prefix coefficient table
|
||||
const prefix_cw_array & prefix_cw_coeff() const noexcept
|
||||
{
|
||||
if constexpr (Wild)
|
||||
return wild_.prefix_cw_coeff;
|
||||
else
|
||||
{
|
||||
static const prefix_cw_array empty{};
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Mark whether a wildcard comparison payload has been assigned.
|
||||
/// @param assigned true once `assign_cmp` has run
|
||||
HEDLEY_NO_THROW
|
||||
void set_assigned(bool assigned) noexcept
|
||||
{
|
||||
if constexpr (Wild)
|
||||
wild_.assigned = assigned;
|
||||
else
|
||||
(void)assigned;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::cmp_meta cmp_{};
|
||||
value_cw_array value_cw_{};
|
||||
|
|
@ -605,33 +742,46 @@ struct cmp_storage
|
|||
cmp_wild_state<Depth, value_cw_word, Wild, TailLen, Idcf> wild_{};
|
||||
};
|
||||
|
||||
/// Multi-level / comparison DPF key body. `PlacedTuple` is a tuple of
|
||||
/// @brief Multi-level / comparison DPF key body. `PlacedTuple` is a tuple of
|
||||
/// `placed<N, T>` slots; `CmpDepth > 0` activates the comparison channel.
|
||||
/// @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
|
||||
/// @tparam PlacedTuple placed tuple
|
||||
/// @tparam CmpDepth cmp depth
|
||||
/// @tparam CmpOutBits cmp out bits
|
||||
/// @tparam CmpWild cmp wild
|
||||
/// @tparam CmpBlock cmp block
|
||||
/// @tparam CmpIdcf cmp idcf
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename PlacedTuple, std::size_t CmpDepth = 0,
|
||||
std::size_t CmpOutBits = 0, bool CmpWild = false,
|
||||
std::size_t CmpBlock = 0, bool CmpIdcf = false>
|
||||
std::size_t CmpBlock = 0, bool CmpIdcf = false,
|
||||
bool IsVerifiable = false, bool IsExtractable = false>
|
||||
struct incr_key_base
|
||||
{
|
||||
public:
|
||||
using interior_prg = InteriorPRG;
|
||||
using exterior_prg = ExteriorPRG;
|
||||
using tree = dpf::tree_traits<InteriorPRG>;
|
||||
using interior_node = typename InteriorPRG::block_type;
|
||||
using exterior_node = typename ExteriorPRG::block_type;
|
||||
using input_type = dpf::concrete_type_t<InputT>;
|
||||
using placed_tuple = PlacedTuple;
|
||||
using node_type = exterior_node;
|
||||
static constexpr std::size_t cmp_depth = CmpDepth;
|
||||
/// Comparison output group width in bits (0 when there is no cmp channel).
|
||||
/// @brief Comparison output group width in bits (0 when there is no cmp channel).
|
||||
static constexpr std::size_t cmp_out_bits = CmpOutBits;
|
||||
/// True when the comparison payload is an unassigned wildcard.
|
||||
/// @brief True when the comparison payload is an unassigned wildcard.
|
||||
static constexpr bool cmp_is_wildcard = CmpWild;
|
||||
/// 0 = per-level path-sum. `B >= 1` = blocked checkpoints of width `B`.
|
||||
/// @brief 0 = per-level path-sum. `B >= 1` = blocked checkpoints of width `B`.
|
||||
static constexpr std::size_t cmp_block = CmpBlock;
|
||||
static constexpr bool cmp_idcf = CmpIdcf;
|
||||
static constexpr bool is_verifiable = IsVerifiable;
|
||||
static constexpr bool is_extractable = IsExtractable;
|
||||
static constexpr std::size_t max_output_level =
|
||||
detail::incr::max_tree_level_v<node_type, PlacedTuple>;
|
||||
/// Residual tail width. 2 only when dropping those levels does not cut an
|
||||
/// @brief Residual tail width. 2 only when dropping those levels does not cut an
|
||||
/// output and the comparison itself is what sets the tree height.
|
||||
static constexpr std::size_t cmp_q = [] {
|
||||
if (CmpBlock == 0 || CmpDepth <= 2)
|
||||
|
|
@ -646,9 +796,7 @@ struct incr_key_base
|
|||
(CmpBlock == 0 || cmp_h == 0) ? 0 : (cmp_h + CmpBlock - 1) / CmpBlock;
|
||||
static constexpr std::size_t cmp_tail =
|
||||
(CmpBlock == 0 || cmp_q == 0) ? 0 : (std::size_t{1} << cmp_q);
|
||||
/// Multi-level / comparison keys route through the slot-aware eval path.
|
||||
static constexpr bool is_multilevel = true;
|
||||
/// Narrowest unsigned word that holds `cmp_out_bits` bits (1 byte for a
|
||||
/// @brief Narrowest unsigned word that holds `cmp_out_bits` bits (1 byte for a
|
||||
/// bit / ≤8-bit payload, 2 for ≤16, 4 for ≤32, 8 for ≤64). Value CWs and
|
||||
/// the addend share are stored in this word.
|
||||
using value_cw_word = utils::integral_type_from_bitlength_t<
|
||||
|
|
@ -667,11 +815,15 @@ struct incr_key_base
|
|||
|
||||
static_assert(num_outputs > 0 || CmpDepth > 0,
|
||||
"incremental DPF needs at least one output or a comparison channel");
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
static_assert(detail::incr::all_prefixes_ok_v<node_type, PlacedTuple>,
|
||||
"at<N> is shorter than the packing lanes required by an output");
|
||||
|
||||
using correction_words_array = std::array<interior_node, depth>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
using correction_advice_array = std::array<psnip_uint8_t, depth>;
|
||||
using correction_seeds_array = std::array<cs_block, IsVerifiable ? depth : 0>;
|
||||
using value_cw_array = std::array<value_cw_word, value_cw_len>;
|
||||
using tail_array = std::array<value_cw_word, cmp_tail>;
|
||||
static constexpr std::size_t prefix_cw_len = CmpIdcf ? depth + 1 : 0;
|
||||
|
|
@ -680,6 +832,26 @@ struct incr_key_base
|
|||
static constexpr meta_array meta =
|
||||
detail::incr::build_meta<node_type, PlacedTuple>();
|
||||
|
||||
/// @brief Multi-level / comparison keys route through the slot-aware eval path.
|
||||
/// Classic-shaped packs (every slot at full input width, no cmp) keep the
|
||||
/// classic `eval_*` fast path even when verifiable/extractable phantoms are
|
||||
/// present.
|
||||
static constexpr bool is_multilevel = [] {
|
||||
if constexpr (CmpDepth > 0)
|
||||
return true;
|
||||
if constexpr (num_outputs == 0)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < num_outputs; ++i)
|
||||
{
|
||||
if (meta[i].prefix != input_bits)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}();
|
||||
|
||||
template <std::size_t I, typename = void>
|
||||
struct output_type_at
|
||||
{
|
||||
|
|
@ -714,7 +886,7 @@ struct incr_key_base
|
|||
public:
|
||||
using leaf_wrapper_tuple = decltype(wrapper_tuple_t(
|
||||
std::make_index_sequence<num_outputs>{}));
|
||||
/// Raw leaf shares (pre-wrapper), matching classic `leaf_tuple` for asio.
|
||||
/// @brief Raw leaf shares (pre-wrapper), matching classic `leaf_tuple` for asio.
|
||||
using leaf_tuple = decltype(leaf_tuple_type(
|
||||
std::make_index_sequence<num_outputs>{}));
|
||||
using offset_type = offset_wrapper<InputT>;
|
||||
|
|
@ -739,7 +911,7 @@ struct incr_key_base
|
|||
}
|
||||
}();
|
||||
|
||||
/// First output (source order) whose prefix equals `deepest_prefix`.
|
||||
/// @brief First output (source order) whose prefix equals `deepest_prefix`.
|
||||
static constexpr std::size_t deepest_output = [] {
|
||||
if constexpr (num_outputs == 0)
|
||||
return std::size_t{0};
|
||||
|
|
@ -754,7 +926,7 @@ struct incr_key_base
|
|||
}
|
||||
}();
|
||||
|
||||
/// Classic-shaped packing traits for deepest-group interval/sequence APIs.
|
||||
/// @brief Classic-shaped packing traits for deepest-group interval/sequence APIs.
|
||||
static constexpr std::size_t outputs_per_leaf =
|
||||
(num_outputs > 0) ? outputs_per_leaf_of<deepest_output> : 1;
|
||||
static constexpr std::size_t lg_outputs_per_leaf =
|
||||
|
|
@ -775,7 +947,8 @@ struct incr_key_base
|
|||
addend_tuple addends = {}, value_cw_array value_cw_coeff = {},
|
||||
uint64_t cw_last_coeff_in = 0, tail_array tail_in = {},
|
||||
tail_array tail_coeff_in = {}, prefix_cw_array prefix_in = {},
|
||||
prefix_cw_array prefix_coeff_in = {})
|
||||
prefix_cw_array prefix_coeff_in = {},
|
||||
correction_seeds_array correction_seeds = {})
|
||||
: leaf_nodes{std::move(leaves)},
|
||||
offset_x{offset_share},
|
||||
cmp_store_{cmp, value_cws,
|
||||
|
|
@ -788,8 +961,9 @@ struct incr_key_base
|
|||
root_{root},
|
||||
correction_words_{correction_words},
|
||||
correction_advice_{correction_advice},
|
||||
correction_seeds_{correction_seeds},
|
||||
common_part_hash_{utils::get_common_part_hash(correction_words_,
|
||||
correction_advice_, leaf_nodes, wildcard_mask)}
|
||||
correction_advice_, leaf_nodes, wildcard_mask, correction_seeds_)}
|
||||
{ }
|
||||
|
||||
incr_key_base(const incr_key_base &) = default;
|
||||
|
|
@ -806,17 +980,63 @@ struct incr_key_base
|
|||
{
|
||||
return correction_advice_;
|
||||
}
|
||||
const correction_seeds_array & correction_seeds() const
|
||||
{
|
||||
return correction_seeds_;
|
||||
}
|
||||
const value_cw_array & value_cw() const { return cmp_store_.value_cw(); }
|
||||
HEDLEY_NO_THROW
|
||||
uint64_t cw_last() const noexcept { return cmp_store_.cw_last(); }
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cw_last_word() const noexcept { return cmp_store_.cw_last_word(); }
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cmp_addend_word() const noexcept
|
||||
{
|
||||
return cmp_store_.cmp_addend_word();
|
||||
}
|
||||
void set_cmp_scalars(value_cw_word last, value_cw_word addend,
|
||||
value_cw_word last_coeff)
|
||||
{
|
||||
cmp_store_.set_scalars(last, addend, last_coeff);
|
||||
}
|
||||
/// @brief Mark whether a wildcard comparison payload has been assigned.
|
||||
/// @param assigned true once `assign_cmp` has run
|
||||
HEDLEY_NO_THROW
|
||||
void set_cmp_assigned(bool assigned) noexcept
|
||||
{
|
||||
cmp_store_.set_assigned(assigned);
|
||||
}
|
||||
const value_cw_array & value_cw_coeff() const noexcept
|
||||
{
|
||||
return cmp_store_.value_cw_coeff();
|
||||
}
|
||||
HEDLEY_NO_THROW
|
||||
value_cw_word cw_last_coeff_word() const noexcept
|
||||
{
|
||||
return cmp_store_.cw_last_coeff_word();
|
||||
}
|
||||
const tail_array & tail_coeff() const noexcept
|
||||
{
|
||||
return cmp_store_.tail_coeff();
|
||||
}
|
||||
const prefix_cw_array & prefix_cw_coeff() const noexcept
|
||||
{
|
||||
return cmp_store_.prefix_cw_coeff();
|
||||
}
|
||||
void assign_cmp_group(const detail::group_elem & delta, value_cw_word addend)
|
||||
{
|
||||
cmp_store_.assign_group(delta, addend);
|
||||
}
|
||||
HEDLEY_NO_THROW
|
||||
const prefix_cw_array & prefix_cws() const noexcept
|
||||
{
|
||||
return cmp_store_.prefix_cws();
|
||||
}
|
||||
uint64_t prefix_cw(std::size_t i) const { return cmp_store_.prefix_cw(i); }
|
||||
/// Party-local share of the constant absorb (`if_false`, or
|
||||
/// @brief Party-local share of the constant absorb (`if_false`, or
|
||||
/// `δ + if_false` when `eval_as_ge`). Reconstructs with the peer share.
|
||||
/// @return Party-local share of the constant absorb (`if_false`, or `δ + if_false` when
|
||||
/// `eval_as_ge`)
|
||||
HEDLEY_NO_THROW
|
||||
uint64_t cmp_addend() const noexcept { return cmp_store_.cmp_addend(); }
|
||||
HEDLEY_NO_THROW
|
||||
|
|
@ -834,8 +1054,9 @@ struct incr_key_base
|
|||
}
|
||||
auto correction_word(std::size_t level, bool direction) const
|
||||
{
|
||||
return set_lo_bit(correction_word(level),
|
||||
(correction_advice_[level] >> direction) & 1);
|
||||
return tree::pack_cw(correction_word(level),
|
||||
correction_advice_[level], direction,
|
||||
tree::is_last_level(level, depth));
|
||||
}
|
||||
uint64_t value_cw(std::size_t level) const { return cmp_store_.value_cw(level); }
|
||||
const tail_array & tail_cw() const { return cmp_store_.tail_cw(); }
|
||||
|
|
@ -879,25 +1100,19 @@ struct incr_key_base
|
|||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
static auto traverse_interior(const interior_node & node,
|
||||
const interior_node & cw, bool dir) noexcept
|
||||
const interior_node & cw, bool dir, bool is_last = false) noexcept
|
||||
{
|
||||
return dpf::xor_if_lo_bit(
|
||||
interior_prg::eval(unset_lo_2bits(node), dir), cw, node);
|
||||
return tree::traverse(node, cw, dir, is_last);
|
||||
}
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
static auto traverse_interior01(const interior_node & node,
|
||||
const interior_node & cw0, const interior_node & cw1) noexcept
|
||||
const interior_node & cw0, const interior_node & cw1,
|
||||
bool is_last = false) noexcept
|
||||
{
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto kids = interior_prg::eval01(unset_lo_2bits(node));
|
||||
return std::array<interior_node, 2>{
|
||||
dpf::xor_if_lo_bit(kids[0], cw0, node),
|
||||
dpf::xor_if_lo_bit(kids[1], cw1, node)};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
return tree::traverse01(node, cw0, cw1, is_last);
|
||||
}
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
|
|
@ -905,22 +1120,9 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
static void traverse_interior01_x4(const interior_node * HEDLEY_RESTRICT parents,
|
||||
const interior_node & cw0, const interior_node & cw1,
|
||||
interior_node * HEDLEY_RESTRICT left,
|
||||
interior_node * HEDLEY_RESTRICT right) noexcept
|
||||
interior_node * HEDLEY_RESTRICT right, bool is_last = false) noexcept
|
||||
{
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
alignas(interior_node) interior_node seeds[4];
|
||||
DPF_UNROLL_LOOP
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
seeds[i] = unset_lo_2bits(parents[i]);
|
||||
interior_prg::eval01_x4(seeds, left, right);
|
||||
DPF_UNROLL_LOOP
|
||||
for (std::size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
left[i] = dpf::xor_if_lo_bit(left[i], cw0, parents[i]);
|
||||
right[i] = dpf::xor_if_lo_bit(right[i], cw1, parents[i]);
|
||||
}
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
tree::traverse01_x4(parents, cw0, cw1, left, right, is_last);
|
||||
}
|
||||
|
||||
template <std::size_t I = 0>
|
||||
|
|
@ -932,33 +1134,49 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
constexpr auto pos =
|
||||
meta[I].pos_base + meta[I].index_in_group * meta[I].block_len;
|
||||
constexpr auto count = meta[I].block_len;
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
using leaf_type = dpf::leaf_node_t<exterior_node, Out>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
leaf_type mask{};
|
||||
auto seed_ =
|
||||
utils::to_exterior_node<exterior_node>(unset_lo_2bits(node));
|
||||
exterior_prg::eval(seed_, leaf_blocks<exterior_node>(mask),
|
||||
static_cast<psnip_uint32_t>(count),
|
||||
static_cast<psnip_uint32_t>(pos));
|
||||
// Subtractive share: CW_if_t − mask so reconstruct(y0, y1) = y0 − y1 = β.
|
||||
if constexpr (IsExtractable)
|
||||
{
|
||||
detail::vdpf::extractable_leaf_prg<exterior_prg>::eval(seed_,
|
||||
leaf_blocks<exterior_node>(mask),
|
||||
static_cast<psnip_uint32_t>(count),
|
||||
static_cast<psnip_uint32_t>(pos));
|
||||
}
|
||||
else
|
||||
{
|
||||
exterior_prg::eval(seed_, leaf_blocks<exterior_node>(mask),
|
||||
static_cast<psnip_uint32_t>(count),
|
||||
static_cast<psnip_uint32_t>(pos));
|
||||
}
|
||||
return dpf::subtract_leaf<Out>(
|
||||
dpf::get_if_lo_bit(std::get<I>(leaf_nodes).get(), node), mask);
|
||||
}
|
||||
|
||||
leaf_wrapper_tuple leaf_nodes;
|
||||
offset_type offset_x;
|
||||
/// Public `if_false` addends for `eq` / `eq_at` slots.
|
||||
/// @brief Public `if_false` addends for `eq` / `eq_at` slots.
|
||||
addend_tuple public_addends{};
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
bool has_cmp() const noexcept { return cmp_store_.has_cmp(); }
|
||||
/// True once a wildcard comparison payload has been assigned (always true
|
||||
/// @brief True once a wildcard comparison payload has been assigned (always true
|
||||
/// for concrete cmp keys and for keys without a comparison channel).
|
||||
/// @return True once a wildcard comparison payload has been assigned (always true for concrete
|
||||
/// cmp keys and for keys without a comparison channel)
|
||||
HEDLEY_NO_THROW
|
||||
bool cmp_assigned() const noexcept { return cmp_store_.cmp_assigned(); }
|
||||
|
||||
/// Patch the value CWs / `cw_last` for a resolved payload δ and install
|
||||
/// @brief Patch the value CWs / `cw_last` for a resolved payload δ and install
|
||||
/// this party's `cmp_addend` share. Only valid for wildcard cmp keys; see
|
||||
/// the free `dpf::assign_cmp`. No tree re-walk / re-PRG.
|
||||
/// @param delta the payload difference `if_true - if_false`
|
||||
/// @param addend_share the `addend_share`
|
||||
void assign_cmp_delta(uint64_t delta, uint64_t addend_share)
|
||||
{
|
||||
cmp_store_.assign_cmp_delta(delta, addend_share);
|
||||
|
|
@ -971,6 +1189,7 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
interior_node root_;
|
||||
correction_words_array correction_words_;
|
||||
correction_advice_array correction_advice_;
|
||||
correction_seeds_array correction_seeds_{};
|
||||
digest_type common_part_hash_;
|
||||
}; // struct incr_key_base
|
||||
|
||||
|
|
@ -1013,7 +1232,13 @@ using dpf_key_base_t = std::conditional_t<
|
|||
OutputT, OutputTs...>::cmp_block,
|
||||
dpf::detail::incr::normalize_pack<
|
||||
utils::bitlength_of_v<dpf::concrete_type_t<InputT>>,
|
||||
OutputT, OutputTs...>::cmp_idcf>>;
|
||||
OutputT, OutputTs...>::cmp_idcf,
|
||||
dpf::detail::incr::normalize_pack<
|
||||
utils::bitlength_of_v<dpf::concrete_type_t<InputT>>,
|
||||
OutputT, OutputTs...>::is_verifiable,
|
||||
dpf::detail::incr::normalize_pack<
|
||||
utils::bitlength_of_v<dpf::concrete_type_t<InputT>>,
|
||||
OutputT, OutputTs...>::is_extractable>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
|
@ -1038,44 +1263,122 @@ namespace detail
|
|||
namespace incr
|
||||
{
|
||||
|
||||
// Assemble the public dpf_key type for a (PlacedTuple, CmpDepth) pair by
|
||||
// expanding the placed slots into the output pack and appending the phantom
|
||||
// cmp tag when a comparison channel is present.
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key
|
||||
// Assemble the public dpf_key type for a (PlacedTuple, CmpDepth, flags) pack by
|
||||
// expanding the placed slots into the output pack and appending phantom tags.
|
||||
//
|
||||
// `dpf_key` always takes an output type. A comparison-only key (empty placed
|
||||
// pack, CmpDepth > 0) is `dpf_key<..., cmp_channel_tag<...>>`. The no-comparison
|
||||
// form is a separate specialization so an empty pack is not named as
|
||||
// `dpf_key<Interior, Exterior, Input>` — `std::conditional_t` would require
|
||||
// that type to be valid even when CmpDepth > 0.
|
||||
template <bool WithCmp, typename InteriorPRG, typename ExteriorPRG,
|
||||
typename InputT, std::size_t CmpDepth, std::size_t CmpOutBits,
|
||||
bool CmpWild, std::size_t CmpBlock, bool CmpIdcf, typename ...Ps>
|
||||
struct plain_assembled_key;
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename ...Ps>
|
||||
struct plain_assembled_key<true, InteriorPRG, ExteriorPRG, InputT,
|
||||
CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, Ps...>
|
||||
{
|
||||
using type = dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...,
|
||||
dpf::cmp_channel_tag<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>>;
|
||||
};
|
||||
template <std::size_t CmpOutBits, bool CmpWild, std::size_t CmpBlock,
|
||||
bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key<0, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, InteriorPRG,
|
||||
ExteriorPRG, InputT, Ps...>
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename P0, typename ...Ps>
|
||||
struct plain_assembled_key<false, InteriorPRG, ExteriorPRG, InputT,
|
||||
CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, P0, Ps...>
|
||||
{
|
||||
using type = dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...>;
|
||||
using type = dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, P0, Ps...>;
|
||||
};
|
||||
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, bool IsVerifiable,
|
||||
bool IsExtractable, typename InteriorPRG, typename ExteriorPRG,
|
||||
typename InputT, typename ...Ps>
|
||||
struct assemble_key;
|
||||
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, false,
|
||||
false, InteriorPRG, ExteriorPRG, InputT, Ps...>
|
||||
{
|
||||
using type = typename plain_assembled_key<(CmpDepth > 0),
|
||||
InteriorPRG, ExteriorPRG, InputT, CmpDepth, CmpOutBits, CmpWild,
|
||||
CmpBlock, CmpIdcf, Ps...>::type;
|
||||
};
|
||||
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, true,
|
||||
false, InteriorPRG, ExteriorPRG, InputT, Ps...>
|
||||
{
|
||||
using with_cmp = std::conditional_t<
|
||||
(CmpDepth > 0),
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...,
|
||||
dpf::cmp_channel_tag<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>,
|
||||
dpf::verifiable>,
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps..., dpf::verifiable>>;
|
||||
using type = with_cmp;
|
||||
};
|
||||
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, false,
|
||||
true, InteriorPRG, ExteriorPRG, InputT, Ps...>
|
||||
{
|
||||
using type = std::conditional_t<
|
||||
(CmpDepth > 0),
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...,
|
||||
dpf::cmp_channel_tag<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>,
|
||||
dpf::extractable>,
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps..., dpf::extractable>>;
|
||||
};
|
||||
|
||||
template <std::size_t CmpDepth, std::size_t CmpOutBits, bool CmpWild,
|
||||
std::size_t CmpBlock, bool CmpIdcf, typename InteriorPRG,
|
||||
typename ExteriorPRG, typename InputT, typename ...Ps>
|
||||
struct assemble_key<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, true,
|
||||
true, InteriorPRG, ExteriorPRG, InputT, Ps...>
|
||||
{
|
||||
using type = std::conditional_t<
|
||||
(CmpDepth > 0),
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...,
|
||||
dpf::cmp_channel_tag<CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>,
|
||||
dpf::verifiable, dpf::extractable>,
|
||||
dpf::dpf_key<InteriorPRG, ExteriorPRG, InputT, Ps...,
|
||||
dpf::verifiable, dpf::extractable>>;
|
||||
};
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename PlacedTuple, std::size_t CmpDepth, std::size_t CmpOutBits = 0,
|
||||
bool CmpWild = false, std::size_t CmpBlock = 0, bool CmpIdcf = false>
|
||||
bool CmpWild = false, std::size_t CmpBlock = 0, bool CmpIdcf = false,
|
||||
bool IsVerifiable = false, bool IsExtractable = false>
|
||||
struct incr_dpf_key_of;
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename ...Ps, std::size_t CmpDepth, std::size_t CmpOutBits,
|
||||
bool CmpWild, std::size_t CmpBlock, bool CmpIdcf>
|
||||
bool CmpWild, std::size_t CmpBlock, bool CmpIdcf,
|
||||
bool IsVerifiable, bool IsExtractable>
|
||||
struct incr_dpf_key_of<InteriorPRG, ExteriorPRG, InputT, std::tuple<Ps...>,
|
||||
CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>
|
||||
CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf, IsVerifiable, IsExtractable>
|
||||
{
|
||||
using type = typename assemble_key<CmpDepth, CmpOutBits, CmpWild, CmpBlock,
|
||||
CmpIdcf, InteriorPRG, ExteriorPRG, InputT, Ps...>::type;
|
||||
CmpIdcf, IsVerifiable, IsExtractable, InteriorPRG, ExteriorPRG, InputT,
|
||||
Ps...>::type;
|
||||
};
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename PlacedTuple, std::size_t CmpDepth, std::size_t CmpOutBits = 0,
|
||||
bool CmpWild = false, std::size_t CmpBlock = 0, bool CmpIdcf = false>
|
||||
bool CmpWild = false, std::size_t CmpBlock = 0, bool CmpIdcf = false,
|
||||
bool IsVerifiable = false, bool IsExtractable = false>
|
||||
using incr_dpf_key_of_t = typename incr_dpf_key_of<InteriorPRG, ExteriorPRG,
|
||||
InputT, PlacedTuple, CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf>::type;
|
||||
InputT, PlacedTuple, CmpDepth, CmpOutBits, CmpWild, CmpBlock, CmpIdcf,
|
||||
IsVerifiable, IsExtractable>::type;
|
||||
|
||||
} // namespace incr
|
||||
} // namespace detail
|
||||
|
|
@ -1167,10 +1470,12 @@ auto make_dpf_impl(dpfargs<InputT, OutputT, OutputTs...> args, root_sampler_t<In
|
|||
|
||||
utils::flip_msb_if_signed_integral(x);
|
||||
|
||||
const interior_node root[2] = {
|
||||
dpf::unset_lo_bit(root_sampler()),
|
||||
dpf::set_lo_bit(root_sampler())
|
||||
};
|
||||
using tree = dpf::tree_traits<InteriorPRG>;
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
interior_node root[2];
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
tree::root_init(root, root_sampler);
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
|
|
@ -1179,32 +1484,29 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
correction_advice_array correction_advice;
|
||||
|
||||
interior_node parent[2] = { root[0], root[1] };
|
||||
bool advice[2];
|
||||
|
||||
for (std::size_t level = 0; level < depth; ++level, mask >>= 1)
|
||||
{
|
||||
bool bit = !!(mask & x);
|
||||
const bool bit = !!(mask & x);
|
||||
const bool is_last = tree::is_last_level(level, depth);
|
||||
const bool ctrl0 = static_cast<bool>(dpf::get_lo_bit(parent[0]));
|
||||
const bool ctrl1 = static_cast<bool>(dpf::get_lo_bit(parent[1]));
|
||||
|
||||
advice[0] = dpf::get_lo_bit_and_clear_lo_2bits(parent[0]);
|
||||
advice[1] = dpf::get_lo_bit_and_clear_lo_2bits(parent[1]);
|
||||
const auto child0 = tree::expand(parent[0], is_last);
|
||||
const auto child1 = tree::expand(parent[1], is_last);
|
||||
|
||||
auto child0 = InteriorPRG::eval01(parent[0]);
|
||||
auto child1 = InteriorPRG::eval01(parent[1]);
|
||||
interior_node child[2] = {
|
||||
child0[0] ^ child1[0],
|
||||
child0[1] ^ child1[1]
|
||||
};
|
||||
interior_node cw{};
|
||||
psnip_uint8_t advice = 0;
|
||||
tree::make_cw(cw, advice, child0, child1, parent[0], parent[1], bit,
|
||||
is_last);
|
||||
|
||||
bool t[2] = {
|
||||
static_cast<bool>(dpf::get_lo_bit(child[0]) ^ !bit),
|
||||
static_cast<bool>(dpf::get_lo_bit(child[1]) ^ bit)
|
||||
};
|
||||
auto cw = dpf::set_lo_bit(child[!bit], t[bit]);
|
||||
parent[0] = dpf::xor_if(child0[bit], cw, advice[0]);
|
||||
parent[1] = dpf::xor_if(child1[bit], cw, advice[1]);
|
||||
parent[0] = tree::advance(parent[0], child0, cw, advice, bit, ctrl0,
|
||||
is_last);
|
||||
parent[1] = tree::advance(parent[1], child1, cw, advice, bit, ctrl1,
|
||||
is_last);
|
||||
|
||||
correction_words[level] = child[!bit];
|
||||
correction_advice[level] = static_cast<psnip_uint8_t>(t[1] << 1) | t[0];
|
||||
correction_words[level] = cw;
|
||||
correction_advice[level] = advice;
|
||||
}
|
||||
|
||||
bool sign0 = dpf::get_lo_bit(parent[0]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue