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
|
|
@ -17,6 +17,7 @@
|
|||
#include <bitset>
|
||||
#include <atomic>
|
||||
|
||||
#include "dpf/experiment_note.hpp"
|
||||
#include "dpf/prg_aes.hpp"
|
||||
#include "dpf/tree_traits.hpp"
|
||||
#include "dpf/wildcard.hpp"
|
||||
|
|
@ -35,6 +36,12 @@ namespace dpf
|
|||
#ifdef LIBDPF_HAS_ASIO
|
||||
namespace asio
|
||||
{
|
||||
/// @brief Exchange a wildcard output share and install the opened leaf.
|
||||
/// @see dpf::leaf_wrapper
|
||||
/// \complexity O(leaf bytes) for the Beaver leaf arithmetic, plus the transfers.
|
||||
/// \rounds 2. Write/read the blinded output share, then write/read the leaf share (`async_assign_wildcard_output`).
|
||||
/// \communication `sizeof(output_type)` plus `sizeof(leaf_type)` each way.
|
||||
/// \preprocessing The leaf Beaver triple (`vector_blind`, `output_blind`, `blinded_vector`) was stored at keygen.
|
||||
template <std::size_t I,
|
||||
typename PeerT,
|
||||
typename DpfKey,
|
||||
|
|
@ -251,14 +258,14 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
const leaf_tuple & leaves,
|
||||
const beaver_tuple & beavers,
|
||||
input_type offset_share)
|
||||
: root_{root},
|
||||
: leaf_nodes(get_wrappers(leaves, beavers)),
|
||||
offset_x{offset_share},
|
||||
root_{root},
|
||||
correction_words_{correction_words},
|
||||
correction_advice_{correction_advice},
|
||||
mutable_wildcard_mask_{dpf::utils::make_bitset(dpf::is_wildcard_v<OutputT>,
|
||||
dpf::is_wildcard_v<OutputTs>...)},
|
||||
leaf_nodes(get_wrappers(leaves, beavers)),
|
||||
common_part_hash_{utils::get_common_part_hash(correction_words_, correction_advice_, leaf_nodes, wildcard_mask)},
|
||||
offset_x{offset_share}
|
||||
common_part_hash_{utils::get_common_part_hash(correction_words_, correction_advice_, leaf_nodes, wildcard_mask)}
|
||||
{ }
|
||||
classic_dpf_key_impl(const classic_dpf_key_impl &) = default;
|
||||
classic_dpf_key_impl(classic_dpf_key_impl &&) = default;
|
||||
|
|
@ -410,6 +417,29 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
return traverse_exterior<I>(node, std::get<I>(leaf_nodes).get());
|
||||
}
|
||||
|
||||
/// @brief Eight one-block leaves. One `eval_x8` instead of eight `eval` calls.
|
||||
template <std::size_t I = 0, typename Out>
|
||||
void traverse_exterior_x8(const interior_node * HEDLEY_RESTRICT nodes,
|
||||
Out * HEDLEY_RESTRICT out) const noexcept
|
||||
{
|
||||
using output_type = std::tuple_element_t<I, concrete_outputs_tuple>;
|
||||
using block = typename exterior_prg::block_type;
|
||||
alignas(64) block seeds[8];
|
||||
alignas(64) block masks[8];
|
||||
for (std::size_t t = 0; t < 8; ++t)
|
||||
seeds[t] = utils::to_exterior_node<block>(unset_lo_2bits(nodes[t]));
|
||||
constexpr auto pos = dpf::block_offset_of_leaf_v<I, block,
|
||||
concrete_outputs_tuple>;
|
||||
exterior_prg::eval_x8(seeds, masks, static_cast<psnip_uint32_t>(pos));
|
||||
const auto & cw = std::get<I>(leaf_nodes).get();
|
||||
for (std::size_t t = 0; t < 8; ++t)
|
||||
{
|
||||
encode_curve_leaf_mask<concrete_type_t<output_type>>(masks[t]);
|
||||
out[t] = dpf::subtract_leaf<output_type>(
|
||||
dpf::get_if_lo_bit(cw, nodes[t]), masks[t]);
|
||||
}
|
||||
}
|
||||
|
||||
leaf_wrapper_tuple leaf_nodes;
|
||||
offset_type offset_x;
|
||||
static constexpr std::array<bool, sizeof...(OutputTs)+1> wildcard_mask{dpf::is_wildcard_v<OutputT>,
|
||||
|
|
@ -670,6 +700,35 @@ struct cmp_storage
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief `mix(base, coeff)` at every value CW, then install `addend`.
|
||||
/// @tparam Mix word rewriter
|
||||
/// @param mix combines one stored base word with its integer coefficient word
|
||||
/// @param addend this party's share of the constant payload
|
||||
template <typename Mix>
|
||||
void assign_payload(Mix mix, value_cw_word addend)
|
||||
{
|
||||
static_assert(Wild,
|
||||
"assign_cmp on a key whose comparison payload is not a wildcard");
|
||||
if constexpr (Wild)
|
||||
{
|
||||
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
|
||||
|
|
@ -767,6 +826,7 @@ struct incr_key_base
|
|||
using interior_node = typename InteriorPRG::block_type;
|
||||
using exterior_node = typename ExteriorPRG::block_type;
|
||||
using input_type = dpf::concrete_type_t<InputT>;
|
||||
using raw_input_type = InputT;
|
||||
using placed_tuple = PlacedTuple;
|
||||
using node_type = exterior_node;
|
||||
static constexpr std::size_t cmp_depth = CmpDepth;
|
||||
|
|
@ -797,10 +857,15 @@ struct incr_key_base
|
|||
static constexpr std::size_t cmp_tail =
|
||||
(CmpBlock == 0 || cmp_q == 0) ? 0 : (std::size_t{1} << cmp_q);
|
||||
/// @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<
|
||||
(CmpOutBits == 0 ? std::size_t{1} : CmpOutBits)>;
|
||||
/// bit / ≤8-bit payload, 2 for ≤16, 4 for ≤32, 8 for ≤64). Payloads wider
|
||||
/// than 256 bits are stored as their raw bytes. Value CWs and the addend
|
||||
/// share use this word.
|
||||
static constexpr std::size_t cmp_word_bits =
|
||||
CmpOutBits == 0 ? std::size_t{1} : CmpOutBits;
|
||||
using value_cw_word = std::conditional_t<
|
||||
(cmp_word_bits <= 256),
|
||||
utils::integral_type_from_bitlength_t<cmp_word_bits>,
|
||||
std::array<std::uint8_t, (cmp_word_bits + 7) / 8>>;
|
||||
|
||||
static constexpr std::size_t num_outputs = std::tuple_size_v<PlacedTuple>;
|
||||
static constexpr std::size_t input_bits = utils::bitlength_of_v<input_type>;
|
||||
|
|
@ -835,12 +900,15 @@ struct incr_key_base
|
|||
/// @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.
|
||||
/// present. `eq` / `eq_at` with a public `if_false` addend also take the
|
||||
/// slot-aware path so party 0 can absorb that addend.
|
||||
static constexpr bool is_multilevel = [] {
|
||||
if constexpr (CmpDepth > 0)
|
||||
return true;
|
||||
if constexpr (num_outputs == 0)
|
||||
return true;
|
||||
else if constexpr (detail::incr::any_public_addend_v<PlacedTuple>)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
for (std::size_t i = 0; i < num_outputs; ++i)
|
||||
|
|
@ -867,6 +935,20 @@ struct incr_key_base
|
|||
template <std::size_t I>
|
||||
using concrete_output_type = concrete_type_t<output_type_t<I>>;
|
||||
|
||||
private:
|
||||
template <std::size_t... Is>
|
||||
static auto outputs_tuple_type(std::index_sequence<Is...>)
|
||||
-> std::tuple<output_type_t<Is>...>;
|
||||
template <std::size_t... Is>
|
||||
static auto concrete_outputs_tuple_type(std::index_sequence<Is...>)
|
||||
-> std::tuple<concrete_output_type<Is>...>;
|
||||
|
||||
public:
|
||||
using outputs_tuple = decltype(outputs_tuple_type(
|
||||
std::make_index_sequence<num_outputs>{}));
|
||||
using concrete_outputs_tuple = decltype(concrete_outputs_tuple_type(
|
||||
std::make_index_sequence<num_outputs>{}));
|
||||
|
||||
template <std::size_t I>
|
||||
static constexpr std::size_t lg_outputs_per_leaf_of =
|
||||
(num_outputs > 0) ? meta[I].lg_opl : 0;
|
||||
|
|
@ -899,6 +981,23 @@ struct incr_key_base
|
|||
static constexpr auto wildcard_mask =
|
||||
wildcard_mask_tuple(std::make_index_sequence<num_outputs>{});
|
||||
|
||||
template <std::size_t... Is>
|
||||
static constexpr std::array<bool, num_outputs>
|
||||
wildcard_mask_array(std::index_sequence<Is...>)
|
||||
{
|
||||
return {{std::get<Is>(wildcard_mask)...}};
|
||||
}
|
||||
static constexpr auto wildcard_bits =
|
||||
wildcard_mask_array(std::make_index_sequence<num_outputs>{});
|
||||
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
constexpr bool is_wildcard(std::size_t i) const noexcept
|
||||
{
|
||||
return i < num_outputs && wildcard_bits[i];
|
||||
}
|
||||
|
||||
static constexpr std::size_t deepest_prefix = [] {
|
||||
if constexpr (num_outputs == 0)
|
||||
return CmpDepth;
|
||||
|
|
@ -938,6 +1037,14 @@ struct incr_key_base
|
|||
using addend_tuple = decltype(addend_tuple_t(
|
||||
std::make_index_sequence<num_outputs>{}));
|
||||
|
||||
static value_cw_word cw_word_from_u64(std::uint64_t v)
|
||||
{
|
||||
if constexpr (std::is_integral_v<value_cw_word>)
|
||||
return static_cast<value_cw_word>(v);
|
||||
else
|
||||
return value_cw_word{};
|
||||
}
|
||||
|
||||
incr_key_base(interior_node root,
|
||||
const correction_words_array & correction_words,
|
||||
const correction_advice_array & correction_advice,
|
||||
|
|
@ -951,13 +1058,13 @@ struct incr_key_base
|
|||
correction_seeds_array correction_seeds = {})
|
||||
: leaf_nodes{std::move(leaves)},
|
||||
offset_x{offset_share},
|
||||
cmp_store_{cmp, value_cws,
|
||||
static_cast<value_cw_word>(cw_last_in),
|
||||
static_cast<value_cw_word>(cmp_addend_in),
|
||||
value_cw_coeff,
|
||||
static_cast<value_cw_word>(cw_last_coeff_in),
|
||||
tail_in, tail_coeff_in, prefix_in, prefix_coeff_in},
|
||||
public_addends{std::move(addends)},
|
||||
cmp_store_{cmp, value_cws,
|
||||
cw_word_from_u64(cw_last_in),
|
||||
cw_word_from_u64(cmp_addend_in),
|
||||
value_cw_coeff,
|
||||
cw_word_from_u64(cw_last_coeff_in),
|
||||
tail_in, tail_coeff_in, prefix_in, prefix_coeff_in},
|
||||
root_{root},
|
||||
correction_words_{correction_words},
|
||||
correction_advice_{correction_advice},
|
||||
|
|
@ -1027,6 +1134,11 @@ struct incr_key_base
|
|||
{
|
||||
cmp_store_.assign_group(delta, addend);
|
||||
}
|
||||
template <typename Mix>
|
||||
void assign_cmp_payload(Mix mix, value_cw_word addend)
|
||||
{
|
||||
cmp_store_.assign_payload(std::move(mix), addend);
|
||||
}
|
||||
HEDLEY_NO_THROW
|
||||
const prefix_cw_array & prefix_cws() const noexcept
|
||||
{
|
||||
|
|
@ -1125,9 +1237,12 @@ struct incr_key_base
|
|||
tree::traverse01_x4(parents, cw0, cw1, left, right, is_last);
|
||||
}
|
||||
|
||||
template <std::size_t I = 0>
|
||||
template <std::size_t I = 0, typename LeafT>
|
||||
HEDLEY_NO_THROW
|
||||
auto traverse_exterior(const interior_node & node) const noexcept
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_PURE
|
||||
static auto traverse_exterior(const interior_node & node,
|
||||
const LeafT & correction_word) noexcept
|
||||
{
|
||||
static_assert(num_outputs > 0, "cmp-only key has no exterior outputs");
|
||||
using Out = concrete_output_type<I>;
|
||||
|
|
@ -1154,8 +1269,50 @@ struct incr_key_base
|
|||
static_cast<psnip_uint32_t>(count),
|
||||
static_cast<psnip_uint32_t>(pos));
|
||||
}
|
||||
encode_curve_leaf_mask<Out>(mask);
|
||||
return dpf::subtract_leaf<Out>(
|
||||
dpf::get_if_lo_bit(std::get<I>(leaf_nodes).get(), node), mask);
|
||||
dpf::get_if_lo_bit(correction_word, node), mask);
|
||||
}
|
||||
|
||||
template <std::size_t I = 0>
|
||||
HEDLEY_NO_THROW
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
auto traverse_exterior(const interior_node & node) const noexcept
|
||||
{
|
||||
static_assert(num_outputs > 0, "cmp-only key has no exterior outputs");
|
||||
return traverse_exterior<I>(node, std::get<I>(leaf_nodes).get());
|
||||
}
|
||||
|
||||
/// @brief Eight one-block leaves, or eight scalar leaves when the PRG is special.
|
||||
template <std::size_t I = 0, typename Out>
|
||||
void traverse_exterior_x8(const interior_node * HEDLEY_RESTRICT nodes,
|
||||
Out * HEDLEY_RESTRICT out) const noexcept
|
||||
{
|
||||
const auto & cw = std::get<I>(leaf_nodes).get();
|
||||
if constexpr (IsExtractable || meta[I].block_len != 1)
|
||||
{
|
||||
for (std::size_t t = 0; t < 8; ++t)
|
||||
out[t] = traverse_exterior<I>(nodes[t], cw);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
using OutT = concrete_output_type<I>;
|
||||
using block = exterior_node;
|
||||
alignas(64) block seeds[8];
|
||||
alignas(64) block masks[8];
|
||||
constexpr auto pos = meta[I].pos_base
|
||||
+ meta[I].index_in_group * meta[I].block_len;
|
||||
for (std::size_t t = 0; t < 8; ++t)
|
||||
seeds[t] = utils::to_exterior_node<block>(unset_lo_2bits(nodes[t]));
|
||||
exterior_prg::eval_x8(seeds, masks, static_cast<psnip_uint32_t>(pos));
|
||||
for (std::size_t t = 0; t < 8; ++t)
|
||||
{
|
||||
encode_curve_leaf_mask<OutT>(masks[t]);
|
||||
out[t] = dpf::subtract_leaf<OutT>(
|
||||
dpf::get_if_lo_bit(cw, nodes[t]), masks[t]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf_wrapper_tuple leaf_nodes;
|
||||
|
|
@ -1383,6 +1540,16 @@ using incr_dpf_key_of_t = typename incr_dpf_key_of<InteriorPRG, ExteriorPRG,
|
|||
} // namespace incr
|
||||
} // namespace detail
|
||||
|
||||
/// @brief One uniform interior node. The default root draw for distributed dealers.
|
||||
template <typename Node>
|
||||
struct uniform_node_sampler
|
||||
{
|
||||
Node operator()() const
|
||||
{
|
||||
return dpf::uniform_sample<Node>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PRG>
|
||||
struct pseudorandom_root_sampler
|
||||
{
|
||||
|
|
@ -1390,7 +1557,10 @@ struct pseudorandom_root_sampler
|
|||
|
||||
pseudorandom_root_sampler(
|
||||
root_type && seed = dpf::uniform_sample<root_type>())
|
||||
: seed_{seed}, counter_{0} { }
|
||||
: seed_{seed}, counter_{0}
|
||||
{
|
||||
note_experiment_seed("pseudorandom_root_sampler", seed_);
|
||||
}
|
||||
|
||||
root_type operator()(psnip_uint32_t i) const
|
||||
{
|
||||
|
|
@ -1528,6 +1698,13 @@ HEDLEY_PRAGMA(GCC diagnostic pop)
|
|||
|
||||
} // namespace detail
|
||||
|
||||
/// @brief Dealer keygen. Returns the two party keys.
|
||||
/// @param args plaintext point and payloads
|
||||
/// @param root_sampler draws the interior roots
|
||||
/// @return a `party_key` pair
|
||||
/// @note Signed domains flip the MSB before the walk (`flip_msb_if_signed_integral`).
|
||||
/// @see dpf::eval_point
|
||||
/// \complexity O(n) time and O(n) key size. n is the domain bitlength (`depth`). The loop does two interior PRG expansions and writes one correction word per level, then builds one exterior leaf per output.
|
||||
template <typename InteriorPRG = dpf::prg::aes128,
|
||||
typename ExteriorPRG = InteriorPRG,
|
||||
typename InputT,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue